http://acm.hdu.edu.cn/webcontest/contest_showproblem.php?pid=1018&ojid=0&cid=12578&hide=0
题意:三种操作 0 l r t,[l,r]的a[i]换成 min(a[i],t),1 l r查询区间最大值,2 l r查询区间的和。
此题的懒惰标记是用最大值。
se表示严格次大值,num表示最大值的个数,t>max不用换,se<t<max时只需换掉最大值,这时改变区间和的改变量tree[id].sum=tree[id].sum+x-tree[id].maxx,其他情况继续分,直到出现上述两种情况。
区间跟新在查询的时候需要pushdown
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int a[maxn];
struct node
{
int id,left,right;
ll sc,maxx,num,sum;
};
node tree[maxn<<2];
void pushup(int id)
{
tree[id].maxx=max(tree[id*2].maxx,tree[id*2+1].maxx);
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
if(tree[id*2].maxx==tree[id*2+1].maxx)
{
tree[id].sc=max(tree[id*2].sc,tree[id*2+1].sc);
tree[id].num=tree[id*2].num+tree[id*2+1].num;
}
else
{
tree[id].sc=max(tree[id*2].sc,tree[id*2+1].sc);
tree[id].sc=max(tree[id].sc,min(tree[id*2].maxx,tree[id*2+1].maxx));
if(tree[id*2].maxx>tree[id*2+1].maxx)
tree[id].num=tree[id*2].num;
else
tree[id].num=tree[id*2+1].num;
}
}
void build(int id,int l,int r)
{
tree[id].left=l;
tree[id].right=r;
if(l==r)
{
tree[id].maxx=a[l];
tree[id].sum=a[l];
tree[id].sc=-1;
tree[id].num=1;
return;
}
int mid=(l+r)/2;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
pushup(id);
}
void putlag(int id,int x)
{
if(x>=tree[id].maxx)
return;
tree[id].sum-=tree[id].num*(tree[id].maxx-x);
tree[id].maxx=x;
}
void pushdown(int id)
{
putlag(id*2,tree[id].maxx);
putlag(id*2+1,tree[id].maxx);
}
void update(int id,int l,int r,int x)
{
if(x>=tree[id].maxx)
return;
if(l<=tree[id].left&&r>=tree[id].right&&tree[id].sc<x)
{
putlag(id,x);
return;
}
pushdown(id);
int mid=(tree[id].left+tree[id].right)/2;
if(r<=mid)
update(id*2,l,r,x);
else if(l>mid)
update(id*2+1,l,r,x);
else
{
update(id*2,l,r,x);
update(id*2+1,l,r,x);
}
/*if(l<=mid)
update(id*2,l,r,x);
if(r>mid)
update(id*2+1,l,r,x);*/
pushup(id);
}
ll querymax(int id,int l,int r)
{
if(l<=tree[id].left&&r>=tree[id].right)
return tree[id].maxx;
pushdown(id);
int mid=(tree[id].left+tree[id].right)/2;
if(r<=mid)
querymax(id*2,l,r);
else if(l>mid)
querymax(id*2+1,l,r);
else
{
return max(querymax(id*2,l,r),querymax(id*2+1,l,r));
}
/*int ans=0;
if(l<=mid)
ans=querymax(id*2,l,r);
if(r>mid)
ans=max(ans,querymax(id*2+1,l,r));
return ans;*/
}
ll querysum(int id,int l,int r)
{
if(l<=tree[id].left&&r>=tree[id].right)
return tree[id].sum;
pushdown(id);
int mid=(tree[id].left+tree[id].right)/2;
if(r<=mid)
querysum(id*2,l,r);
else if(l>mid)
querysum(id*2+1,l,r);
else
{
return querysum(id*2,l,r)+querysum(id*2+1,l,r);
}
/*int ans=0;
if(l<=mid)
ans+=querysum(id*2,l,r);
if(r>mid)
ans+=querysum(id*2+1,l,r);
return ans;*/
}
int main()
{
ll t,n,m,x,y,i,z,w;
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld",&n,&m);
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
while(m--)
{
scanf("%lld",&w);
if(w==0)
{
scanf("%lld%lld%lld",&x,&y,&z);
update(1,x,y,z);
}
else if(w==1)
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",querymax(1,x,y));
}
else
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",querysum(1,x,y));
}
}
}
}