题意: 给一个序列,初始全为0,然后有4种操作:
1. 给区间[L,R]所有值+c
2.给区间[L,R]所有值乘c
3.设置区间[L,R]所有值为c
4.查询[L,R]的p次方和(1<=p<=3)
解法: 线段树,维护三个标记,addmark,mulmark,setmark分别表示3种更新,然后p[1],p[2],p[3]分别表示该节点的1,2,3次方和。标记传递顺序setmark一定是第一个,因为setmark可以使mulmark,addmark都失效还原,mulmark和addmark的顺序倒是无所谓。
这题写了半个比赛时间,写的很迷,还是没写出来, 后来看了别人写的,才知道自己很多地方都没更新好甚至没更新。这题算是一道线段树的综合题了,混合了几种常见的更新,对线段树的整体把握很有帮助。
比如:
1.如果setmark有值,那么addmark,mulmark全部要还原。
2.如果mulmark有值,那么addmark也要更新,更新为addmark*mulmark
就是这两点一直没考虑到,WA了好久。
在addmark下传过程中更新p[1],p[2],p[3]的方法如下:
比如 a^3 -> (a+c)^3 的过程: (a+c)^3 = a^3 + c^3 + 3a*c^2 + 3*a^2*c, a是变量, 所以提取出c,那么p[3]可以由p[1],p[2]推出,p[2]可以由p[1]推出。
即 p[3] = p[3] + c^3 + 3*c^2*p[1] + 3*c*p[2] .
p[2]同理可以由p[1]推出。
然后每次都做一下pushdown,就可以得出正确答案。
当时像优化一下,少做几次pushdown,即这次的操作类型与上次一样就不pushdown,结果那样就会出现问题,还不如每次都pushdown呢。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define Mod 10007 #define SMod 10007 using namespace std; #define N 100017 struct node{ int p[4]; int setmark,addmark,mulmark; }tree[4*N]; void pushup(int rt){ for(int i=1;i<=3;i++) tree[rt].p[i] = (tree[2*rt].p[i] + tree[2*rt+1].p[i])%SMod; } void pushdown(int l,int r,int rt) { int mid = (l+r)/2; if(tree[rt].setmark) { int mk = tree[rt].setmark; tree[rt<<1].setmark = tree[rt<<1|1].setmark = mk; tree[rt<<1].addmark = tree[rt<<1|1].addmark = 0; tree[rt<<1].mulmark = tree[rt<<1|1].mulmark = 1; tree[rt<<1].p[1] = (mid-l+1)%Mod*mk%SMod; tree[rt<<1|1].p[1] = (r-mid)%Mod*mk%SMod; tree[rt<<1].p[2] = (mid-l+1)%Mod*mk%SMod*mk%SMod; tree[rt<<1|1].p[2] = (r-mid)%Mod*mk%SMod*mk%SMod; tree[rt<<1].p[3] = (mid-l+1)%Mod*mk%SMod*mk%SMod*mk%SMod; tree[rt<<1|1].p[3] = (r-mid)%Mod*mk%SMod*mk%SMod*mk%SMod; tree[rt].setmark = 0; } if(tree[rt].mulmark != 1) { int mk = tree[rt].mulmark; tree[rt<<1].mulmark *= mk, tree[rt<<1].mulmark%=SMod; tree[rt<<1|1].mulmark *= mk, tree[rt<<1|1].mulmark%=SMod; tree[rt<<1].addmark = tree[rt<<1].addmark%SMod*mk%SMod; tree[rt<<1|1].addmark = tree[rt<<1|1].addmark%SMod*mk%SMod; tree[rt<<1].p[1] = tree[rt<<1].p[1]%Mod*mk%SMod; tree[rt<<1|1].p[1] = tree[rt<<1|1].p[1]%Mod*mk%SMod; tree[rt<<1].p[2] = tree[rt<<1].p[2]%Mod*mk%SMod*mk%SMod; tree[rt<<1|1].p[2] = tree[rt<<1|1].p[2]%Mod*mk%SMod*mk%SMod; tree[rt<<1].p[3] = tree[rt<<1].p[3]%Mod*mk%SMod*mk%SMod*mk%SMod; tree[rt<<1|1].p[3] = tree[rt<<1|1].p[3]%Mod*mk%SMod*mk%SMod*mk%SMod; tree[rt].mulmark = 1; } if(tree[rt].addmark) { int mk = tree[rt].addmark; tree[rt<<1].addmark += mk, tree[rt<<1].addmark%SMod; tree[rt<<1|1].addmark += mk, tree[rt<<1|1].addmark%SMod; tree[rt<<1].p[3] = (tree[rt<<1].p[3]%Mod + (mid-l+1)%Mod*mk%SMod*mk%SMod*mk%SMod + 3*mk%Mod*tree[rt<<1].p[2]%SMod + 3*mk%SMod*mk%SMod*tree[rt<<1].p[1]%SMod)%SMod; tree[rt<<1|1].p[3] = (tree[rt<<1|1].p[3]%Mod + (r-mid)%Mod*mk%SMod*mk%SMod*mk%SMod + 3*mk%Mod*tree[rt<<1|1].p[2]%SMod + 3*mk%SMod*mk%SMod*tree[rt<<1|1].p[1]%SMod)%SMod; tree[rt<<1].p[2] = (tree[rt<<1].p[2]%Mod + (mid-l+1)%Mod*mk%SMod*mk%SMod + 2*mk%Mod*tree[rt<<1].p[1]%SMod)%SMod; tree[rt<<1|1].p[2] = (tree[rt<<1|1].p[2]%Mod + (r-mid)%Mod*mk%SMod*mk%SMod + 2*mk%Mod*tree[rt<<1|1].p[1]%SMod)%SMod; tree[rt<<1].p[1] = (tree[rt<<1].p[1]%Mod + (mid-l+1)%Mod*mk%SMod)%SMod; tree[rt<<1|1].p[1] = (tree[rt<<1|1].p[1]%Mod + (r-mid)%Mod*mk%SMod)%SMod; tree[rt].addmark = 0; } } void build(int l,int r,int rt) { tree[rt].setmark = tree[rt].addmark = 0; tree[rt].mulmark = 1; memset(tree[rt].p,0,sizeof(tree[rt].p)); if(l == r) return; int mid = (l+r)/2; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); } void update(int l,int r,int aa,int bb,int tag,int val,int rt) //tag = 3 : set 2:mul 1: add { if(aa <= l && bb >= r) { if(tag == 3) { tree[rt].p[1] = (r-l+1)%Mod*val%SMod; tree[rt].p[2] = (r-l+1)%Mod*val%SMod*val%SMod; tree[rt].p[3] = (r-l+1)%Mod*val%SMod*val%SMod*val%SMod; tree[rt].setmark = val; tree[rt].addmark = 0; tree[rt].mulmark = 1; } else if(tag == 2) { tree[rt].p[1] = tree[rt].p[1]%SMod*val%SMod; tree[rt].p[2] = tree[rt].p[2]%SMod*val%SMod*val%SMod; tree[rt].p[3] = tree[rt].p[3]%SMod*val%SMod*val%SMod*val%SMod; tree[rt].mulmark = tree[rt].mulmark%SMod*val%SMod; tree[rt].addmark = tree[rt].addmark%SMod*val%SMod; } else if(tag == 1) { tree[rt].p[3] = (tree[rt].p[3]%SMod + (r-l+1)%SMod*val%SMod*val%SMod*val%SMod + 3*val%SMod*tree[rt].p[2]%SMod + 3*val%SMod*val%SMod*tree[rt].p[1]%SMod)%SMod; tree[rt].p[2] = (tree[rt].p[2]%SMod + (r-l+1)%SMod*val%SMod*val%SMod + 2*val%SMod*tree[rt].p[1]%SMod)%SMod; tree[rt].p[1] = (tree[rt].p[1]%SMod + (r-l+1)%SMod*val%SMod)%SMod; tree[rt].addmark = (tree[rt].addmark+val)%SMod; } return; } int mid = (l+r)/2; pushdown(l,r,rt); if(aa <= mid) update(l,mid,aa,bb,tag,val,rt<<1); if(bb > mid) update(mid+1,r,aa,bb,tag,val,rt<<1|1); pushup(rt); } int query(int l,int r,int aa,int bb,int i,int rt) { if(aa > r || bb < l) return 0; if(aa <= l && bb >= r) return tree[rt].p[i]; pushdown(l,r,rt); int res = 0; int mid = (l+r)/2; return (query(l,mid,aa,bb,i,rt<<1)%SMod+query(mid+1,r,aa,bb,i,rt<<1|1)%SMod)%SMod; } int main() { int n,m,i,j,op,x,y,c; while(scanf("%d%d",&n,&m)!=EOF && n+m) { build(1,n,1); while(m--) { scanf("%d%d%d%d",&op,&x,&y,&c); if(op != 4) update(1,n,x,y,op,c,1); else printf("%d\n",query(1,n,x,y,c,1)%SMod); } } return 0; }