继续补专题
题目思路
题目给出三种操作
查询区间最大值
查询区间和
给出数据v 将区间中每个点修改为min(a[i],v)
前面两个是基本的线段树操作 很好实现
但第三个就不好实现了,也是本题的难点
如果对区间内每个点做修改 时间复杂度上太大 这里要用lazy_tag的思想
还有注意数据范围 记得开ll(wa了无数次了 菜鸡落泪)
以下图片据说是16年国家集训队jls的论文 也是本题的主要思路
ac代码
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 2e5+10;
const int inf = 0x1f1f1f1f;
const int mod = 2333;
ll a[maxn];
//从左往右四个数组分别记录区间和,区间最大值,区间严格次大值,区间最大值出现的次数
ll tsum[maxn<<2],tmax[maxn<<2],tse[maxn<<2],tcnt[maxn<<2];
//本题重要函数 内容有点绕 之前这里写搓了wa了挺多发 写的时候建议先理清思路归好类 不要直接一个情况一个情况的特判
void pushup(int rt)
{
tsum[rt]=tsum[lson]+tsum[rson];
tmax[rt]=max(tmax[lson],tmax[rson]);
if(tmax[lson]==tmax[rson])
{
tse[rt]=max(tse[lson],tse[rson]);
tcnt[rt]=tcnt[lson]+tcnt[rson];
}else
{
tse[rt]=min(tmax[lson],tmax[rson]);
tse[rt]=max(tse[rt],max(tse[lson],tse[rson]));
if(tmax[rt]==tmax[lson])
tcnt[rt]=tcnt[lson];
else
tcnt[rt]=tcnt[rson];
}
}
//lazy_tag 不同于我之前学的直接用lazy数组记录 这里因为改变了最大值 直接进行比较 大于当前最大值的话 那么这个区间是要被修改 但还未被修改的区间
void pushtag(int rt,int x)
{
if(x>=tmax[rt])return;
tsum[rt]-=tcnt[rt]*(tmax[rt]-x);
tmax[rt]=x;
}
void pushdown(int rt)
{
pushtag(lson,tmax[rt]);
pushtag(rson,tmax[rt]);
}
void build(int rt,int l,int r)
{
if(l==r)//将维护的多个信息初始化
{
tmax[rt]=tsum[rt]=a[l];
tse[rt]=0;
tcnt[rt]=1;
return;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
}
void change(int L,int R,int l,int r,int v,int rt)
{
if(tmax[rt]<=v)
{
return;
}
if(tse[rt]<v&&L<=l&&r<=R)
{
pushtag(rt,v);
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid)
change(L,R,l,mid,v,lson);
if(R>mid)
change(L,R,mid+1,r,v,rson);
pushup(rt);
}
ll query_sum(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
return tsum[rt];
}
int mid=(l+r)>>1;
pushdown(rt);
ll res=0;
if(L<=mid)
res+=query_sum(L,R,l,mid,lson);
if(R>mid)
res+=query_sum(L,R,mid+1,r,rson);
return res;
}
ll query_max(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
return tmax[rt];
}
int mid=(l+r)>>1;
pushdown(rt);
ll res=0;
if(L<=mid)
res=max(res,query_max(L,R,l,mid,lson));
if(R>mid)
res=max(res,query_max(L,R,mid+1,r,rson));
return res;
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
build(1,1,n);
while(q--)
{
int tp;
scanf("%d",&tp);
if(tp==0)
{
int l,r,v;
scanf("%d%d%d",&l,&r,&v);
change(l,r,1,n,v,1);
}
if(tp==1)
{
int l,r;
scanf("%d%d",&l,&r);
ll ans=query_max(l,r,1,n,1);
printf("%lld\n",ans);
}
if(tp==2)
{
int l,r;
scanf("%d%d",&l,&r);
ll ans=query_sum(l,r,1,n,1);
printf("%lld\n",ans);
}
}
}
}