Submit: 1179 Solved: 392
[Submit][Status][Discuss]
Description
有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问[a,b]这一段区间中选择c个数相乘的所有方案的和mod 19940417的值。
Input
第一行两个数n,q表示序列长度和操作个数。
第二行n个非负整数,表示序列。
接下来q行每行输入一个操作I a b c或者 R a b或者Q a b c意义如题目描述。
Output
对于每个询问,输出选出c个数相乘的所有方案的和mod19940417的值。
Sample Input
5 5
1 2 3 4 5
I 2 3 1
Q 2 4 2
R 1 5
I 1 3 -1
Q 1 5 1
1 2 3 4 5
I 2 3 1
Q 2 4 2
R 1 5
I 1 3 -1
Q 1 5 1
Sample Output
40
19940397
样例说明
做完第一个操作序列变为1 3 4 4 5。
第一次询问结果为3*4+3*4+4*4=40。
做完R操作变成-1 -3 -4 -4 -5。
做完I操作变为-2 -4 -5 -4 -5。
第二次询问结果为-2-4-5-4-5=-20。
19940397
样例说明
做完第一个操作序列变为1 3 4 4 5。
第一次询问结果为3*4+3*4+4*4=40。
做完R操作变成-1 -3 -4 -4 -5。
做完I操作变为-2 -4 -5 -4 -5。
第二次询问结果为-2-4-5-4-5=-20。
HINT
100%的数据n<=50000,q<=50000,初始序列的元素的绝对值<=109,I a b c中保证[a,b]是一个合法区间,|c|<=109,R a b保证[a,b]是个合法的区间。Q a b c中保证[a,b]是个合法的区间1<=c<=min(b-a+1,20)。
Source
码农级线段树题目,,,
子树合并很好想,就是一个卷积;
标记下传也很好想,我的写法的话是先下传正负再下传add。
正负修改也很好想,把add和tag打一下标记然后把i是奇数的f[]变成它的相反数即可。
就是区间加之后的维护有点难度,要推一推式子,但是这里我懒得再推一遍了23333。
#include<bits/stdc++.h> #define ll long long #define maxn 50005 #define ha 19940417 using namespace std; int C[maxn][25],n,m,tp,num; int a[maxn],le,ri,w,ci[25]; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x; } inline void init(){ C[0][0]=1; for(int i=1;i<=n;i++){ tp=min(i,20); C[i][0]=1; for(int j=1;j<=tp;j++) C[i][j]=add(C[i-1][j-1],C[i-1][j]); } } struct node{ int tag,ad; int c[25]; inline void clear(){ memset(c,0,sizeof(c)); tag=ad=0; } node operator +(const node &U)const{ node r; r.clear(); for(int i=0;i<=20;i++) if(c[i]) for(int j=i;j<=20;j++) if(U.c[j-i]) r.c[j]=add(r.c[j],c[i]*(ll)U.c[j-i]%ha); return r; } }b[maxn<<2|1],AN; char ch; void build(int o,int l,int r){ if(l==r){ b[o].c[0]=1; b[o].c[1]=a[l]; return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; build(lc,l,mid); build(rc,mid+1,r); b[o]=b[lc]+b[rc]; } inline void work(int o,int d,int len){ tp=min(len,20); ci[0]=1; for(int i=1;i<=tp;i++) ci[i]=ci[i-1]*(ll)d%ha; b[o].ad=add(b[o].ad,d); for(int i=20;i;i--){ int S=i,T=len; for(int j=0;j<i;j++,S--,T--){ b[o].c[i]=add(b[o].c[i],b[o].c[j]*(ll)ci[i-j]%ha*(ll)C[T][S]%ha); } } } inline void rotate(int o,int len){ b[o].tag^=1,b[o].ad=ha-b[o].ad; for(int i=1;i<=20;i+=2) b[o].c[i]=ha-b[o].c[i]; } inline void pushdown(int o,int l,int r){ int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; if(b[o].tag){ rotate(lc,mid-l+1); rotate(rc,r-mid); b[o].tag=0; } if(b[o].ad){ work(lc,b[o].ad,mid-l+1); work(rc,b[o].ad,r-mid); b[o].ad=0; } } void updateX(int o,int l,int r){ if(l>=le&&r<=ri){ work(o,w,r-l+1); return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; pushdown(o,l,r); if(le<=mid) updateX(lc,l,mid); if(ri>mid) updateX(rc,mid+1,r); b[o]=b[lc]+b[rc]; } void updateY(int o,int l,int r){ if(l>=le&&r<=ri){ rotate(o,r-l+1); return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; pushdown(o,l,r); if(le<=mid) updateY(lc,l,mid); if(ri>mid) updateY(rc,mid+1,r); b[o]=b[lc]+b[rc]; } void query(int o,int l,int r){ if(l>=le&&r<=ri){ AN=AN+b[o]; return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; pushdown(o,l,r); if(le<=mid) query(lc,l,mid); if(ri>mid) query(rc,mid+1,r); } int main(){ scanf("%d%d",&n,&m); init(); for(int i=1;i<=n;i++){ scanf("%d",a+i); a[i]%=ha; if(a[i]<0) a[i]+=ha; } build(1,1,n); while(m--){ ch=getchar(); while(ch!='I'&&ch!='R'&&ch!='Q') ch=getchar(); scanf("%d%d",&le,&ri); if(ch=='R') updateY(1,1,n); else{ scanf("%d",&w); if(ch=='Q'){ AN.clear(); AN.c[0]=1; query(1,1,n); printf("%d ",AN.c[w]); } else{ w%=ha; if(w<0) w+=ha; updateX(1,1,n); } } } return 0; }