2151: 集训难度
Submit Page Summary Time Limit: 1 Sec Memory Limit: 512 Mb Submitted: 124 Solved: 34
Description
小L正在组织acm暑假集训,但众所周知,暑假集训的萌新中有OI神犇,也有暑假才开始学算法的萌新,如果统一集训的难度,无法很好地让萌新们得到训练,所以小L想了一个办法,根据每次测试的情况,改变萌新们的集训难度。现在将萌新们编号为1到n,最初萌新们的集训难度为v0,测试后有两种操作,第一种是某一区间的萌新的集训难度同时提高,另一种是将某一段区间的萌新的集训难度变为同一个数,同时,Wells希望在某次调整难度之后,知道某一段区间的萌新的集训难度之和,由于小L比较鶸,他并不知道如何快速解决这个问题,你能帮帮他嘛?
Input
第一行三个数n,m,v0 表示有n名萌新和m次调整,初始时全部萌新的集训难度都为v0
第2~m+1行 每行三个数或四个数
0 x y v 表示把 [x,y]区间内的萌新的集训难度都增加v
1 x y v 表示把 [x,y]区间内的萌新的集训难度都变为v
2 x y表示询问[x,y]区间内萌新的集训难度之和
0<n,m<=10^5, |v|<=10^5
Output
每个询问一行,输出答案
Sample Input
3 5 0 0 1 3 1 1 2 3 2 2 1 1 2 2 2 2 2 3
Sample Output
1 2 4
线段树模板题,特别的地方是同时有更新与累加操作,那么就需要两个tag,而我这里转换了一下,用tag表示累加,re表示更新值。
另外关注一下changetag的整体写法,推荐先维护好本结点,tag与re标记的是要更新下一节点这样子的状态,changetag函数放在后面也在时间空间更优叭。
代码:
#include <cstdio>
#include <cstring>
const int maxn=1e5+20;
int n,m,v;
struct node{
int l,r;
int re;
long long sum,tag;
};
node tree[maxn<<2];
void build(int k,int l,int r)
{
tree[k].l=l;tree[k].r=r;
tree[k].sum=1ll*(r-l+1)*v; //一开始写反了
tree[k].tag=0;tree[k].re=0;
if(l==r) return;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
void changetag(int k)
{
int mid=(tree[k].l+tree[k].r)>>1;
if(tree[k].re){
tree[k].re=0;
tree[k<<1].re=tree[k<<1|1].re=1;
tree[k<<1].tag=tree[k<<1|1].tag=0;
tree[k<<1].sum=tree[k<<1|1].sum=0;
}
tree[k<<1].tag+=tree[k].tag;
tree[k<<1|1].tag+=tree[k].tag;
tree[k<<1].sum+=1ll*(mid-tree[k].l+1)*tree[k].tag; //两个int相乘有可能溢出,1ll*可防止
tree[k<<1|1].sum+=1ll*(tree[k].r-mid)*tree[k].tag;
tree[k].tag=0;
}
void add(int k,int l,int r,int x)
{
if(tree[k].l==l&&tree[k].r==r){
tree[k].tag+=x;
tree[k].sum+=1ll*(r-l+1)*x;
return;
}
if(tree[k].tag||tree[k].re) //写在这里省空间,表示的是传递给下一层的,本结点已经维护好了
changetag(k);
int mid=(tree[k].l+tree[k].r)>>1;
if(r<=mid)
add(k<<1,l,r,x);
else if(l>=mid+1)
add(k<<1|1,l,r,x);
else{
add(k<<1,l,mid,x);
add(k<<1|1,mid+1,r,x);
}
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
void update(int k,int l,int r,int x)
{
if(tree[k].l==l&&tree[k].r==r){
tree[k].re=1;
tree[k].tag=x;
tree[k].sum=1ll*(r-l+1)*x;
return;
}
if(tree[k].tag||tree[k].re)
changetag(k);
int mid=(tree[k].l+tree[k].r)>>1;
if(r<=mid)
update(k<<1,l,r,x);
else if(l>=mid+1)
update(k<<1|1,l,r,x);
else{
update(k<<1,l,mid,x);
update(k<<1|1,mid+1,r,x);
}
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
long long query(int k,int l,int r)
{
if(tree[k].l==l&&tree[k].r==r){
return tree[k].sum;
}
if(tree[k].tag||tree[k].re)
changetag(k);
int mid=(tree[k].l+tree[k].r)>>1;
if(r<=mid)
return query(k<<1,l,r);
else if(l>=mid+1)
return query(k<<1|1,l,r);
else
return query(k<<1,l,mid)+query(k<<1|1,mid+1,r);
}
int main()
{
int com,x,y;
while(~scanf("%d%d%d",&n,&m,&v)){
memset(tree,0,sizeof(tree));
build(1,1,n);
for(int i=0;i<m;++i){
scanf("%d",&com);
switch(com){
case 0:
scanf("%d%d%d",&x,&y,&v);
add(1,x,y,v);
break;
case 1:
scanf("%d%d%d",&x,&y,&v);
update(1,x,y,v);
break;
case 2:
scanf("%d%d",&x,&y);
printf("%lld\n",query(1,x,y));
break;
default: break;
}
}
}
return 0;
}