您的位置:首页 > 其它

线段树lazy标记2

2017-12-19 16:22 211 查看
Description

给定一个正整数序列A,要求支持以下操作:

1):ADD a b c 表示在[a,b]上加上一个常数C。

2):COVER a b c 把[a,b]整体赋值为一个常数K。

3):QUERY a b 查询[a,b]的sum。

Input

第一行两个正整数n、m,n表示序列长度,m表示操作数。

第二行n个正整数,第i表示Ai的大小。

接下来的m行,每行有且仅有一种操作,具体和题目描述一致。

n,m<=100000,其他权值都<=50000,小心爆int。

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个标记:icoveri表示这个点是否在下传标记后被覆盖。coveri表示这个点被覆盖成了什么值。sumi表示这个点被增加了多少。下传时先考虑cover的下传,再考虑sum的下传。注意每次一个点被覆盖后这个点的sum值都要被赋成0。

代码

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: