Description
给定一个正整数序列
1):ADD
2):COVER
3):QUERY
Input
第一行两个正整数
第二行
接下来的
Output
对于每个询问操作,输出答案。
Sample Input
10 10
17 18 16 12 13 7 13 6 11 20
QUERY 5 6
QUERY 2 7
ADD 1 6 13
QUERY 4 10
ADD 2 5 18
COVER 2 8 11
ADD 6 9 5
QUERY 8 8
ADD 6 9 18
QUERY 5 7
Sample Output
20
79
121
16
79
HINT
思路
记录3个标记:
代码
#include <cstdio>
const int maxn=100000;
long long a[maxn+10];
struct segment_tree
{
long long val[(maxn<<2)+10],sum[(maxn<<2)+10],cover[(maxn<<2)+10];
int icover[(maxn<<2)+10];
inline int updata(int now)//更新这个点的val
{
val[now]=val[now<<1]+val[now<<1|1];
return val[now];
}
inline int pushdown(int now,int left,int right)//下传标记
{
int mid=(left+right)>>1;
if(icover[now])//如果这个点被cover过,下传cover标记
{
icover[now]=0;
cover[now<<1]=cover[now];
sum[now<<1]=0;//注意sum标记要赋成0
val[now<<1]=cover[now]*(mid-left+1);
cover[now<<1|1]=cover[now];
sum[now<<1|1]=0;
val[now<<1|1]=cover[now]*(right-mid);
icover[now<<1]=icover[now<<1|1]=1;//表示被覆盖过
}
sum[now<<1]+=sum[now];//下传sum标记
val[now<<1]+=sum[now]*(mid-left+1);
sum[now<<1|1]+=sum[now];
val[now<<1|1]+=sum[now]*(right-mid);
sum[now]=0;
return 0;
}
int build(int now,int left,int right)//建树
{
if(left==right)
{
icover[now]=0;//初始化
sum[now]=0;
val[now]=a[left];
return 0;
}
int mid=(left+right)>>1;
build(now<<1,left,mid);
build(now<<1|1,mid+1,right);
updata(now);
return 0;
}
int rcover(int now,int left,int right,int askl,int askr,long long cval)
//将一个区间[left,right]cover成cval
{
if((askl<=left)&&(right<=askr))
{
icover[now]=1;//覆盖
cover[now]=cval;
sum[now]=0;//注意
val[now]=cval*(right-left+1);
return 0;
}
int mid=(left+right)>>1;
pushdown(now,left,right);
if(askl<=mid)
{
rcover(now<<1,left,mid,askl,askr,cval);
}
if(mid<askr)
{
rcover(now<<1|1,mid+1,right,askl,askr,cval);
}
updata(now);
return 0;
}
int add(int now,int left,int right,int askl,int askr,long long cval)
//将一个区间的值增加
{
if((askl<=left)&&(right<=askr))
{
sum[now]+=cval;
val[now]+=cval*(right-left+1);
return 0;
}
int mid=(left+right)>>1;
pushdown(now,left,right);
if(askl<=mid)
{
add(now<<1,left,mid,askl,askr,cval);
}
if(mid<askr)
{
add(now<<1|1,mid+1,right,askl,askr,cval);
}
updata(now);
return 0;
}
long long getsum(int now,int left,int right,int askl,int askr)
//求一段区间的和
{
if((askl<=left)&&(right<=askr))
{
return val[now];
}
int mid=(left+right)>>1;
long long res=0;
pushdown(now,left,right);
if(askl<=mid)
{
res+=getsum(now<<1,left,mid,askl,askr);
}
if(mid<askr)
{
res+=getsum(now<<1|1,mid+1,right,askl,askr);
}
return res;
}
};
segment_tree st;
int n,m,aa,b;
long long c;
char s[10];
int main()
{
scanf("%d%d",&n,&m);
for(register int i=1; i<=n; ++i)
{
scanf("%lld",&a[i]);
}
st.build(1,1,n);
while(m--)
{
scanf("%s%d%d",s,&aa,&b);
if(s[0]=='Q')
{
printf("%lld\n",st.getsum(1,1,n,aa,b));
}
else if(s[0]=='C')
{
scanf("%lld",&c);
st.rcover(1,1,n,aa,b,c);
}
else
{
scanf("%lld",&c);
st.add(1,1,n,aa,b,c);
}
}
return 0;
}