P3278 [SCOI2013]多項式的運算 題解
阿新 • • 發佈:2022-05-19
前兩個操作放過來看似是一道線段樹題,但是發現線段樹無法維護第三個操作。考慮使用平衡樹(fhqtreap)來解決這個問題,前兩個操作和線段樹差不多,直接split出來打加法和乘法標記即可。第三個操作大概就是把 \(R\) 位置的係數加到 \(R+1\) 位置並且刪除,在 \(L\) 的左邊加一個 \(0\),這樣就相當於完成了一次平移。統計答案的時候,因為次數很少,所以可以使用一些 \(O(n)\) 的方式。比如,每次都split出來最右邊的那個位置的係數,直接計算即可。
點選檢視程式碼
#include<iostream> #include<cstdio> #include<chrono> #include<cstring> #include<random> using namespace std; unsigned int seed=chrono::system_clock::now().time_since_epoch().count(); mt19937 rand_num(seed); const int N=1e5+13,P=20130426; struct Fhqtreap{int siz,ls,rs,prio,val,add,mul;}t[N]; int tot; inline int newnode(){t[++tot]=(Fhqtreap){1,0,0,(int)rand_num()%P,0,0,1};return tot;} inline void refresh(int p){t[p].siz=t[t[p].ls].siz+t[t[p].rs].siz+1;} inline void pushup_add(int p,int x){ t[p].add=(t[p].add+x)%P; t[p].val=(t[p].val+x)%P; } inline void pushup_mul(int p,int x){ t[p].add=1ll*t[p].add*x%P; t[p].mul=1ll*t[p].mul*x%P; t[p].val=1ll*t[p].val*x%P; } inline void pushdown(int p){ if(t[p].mul!=1){ pushup_mul(t[p].ls,t[p].mul); pushup_mul(t[p].rs,t[p].mul); t[p].mul=1; } if(t[p].add){ pushup_add(t[p].ls,t[p].add); pushup_add(t[p].rs,t[p].add); t[p].add=0; } } int merge(int p,int q){ if(!p||!q) return p+q; if(t[p].prio<t[q].prio){ pushdown(p); t[p].rs=merge(t[p].rs,q); refresh(p); return p; } pushdown(q); t[q].ls=merge(p,t[q].ls); refresh(q); return q; } void split(int now,int k,int &p,int &q){ if(!now){p=q=0;return;} pushdown(now); if(t[t[now].ls].siz<k) p=now,split(t[now].rs,k-t[t[now].ls].siz-1,t[now].rs,q); else q=now,split(t[now].ls,k,p,t[now].ls); refresh(now); } int main(){ int m,rt=0,lim=1e5+2; scanf("%d",&m); for(int i=1;i<=lim;++i) rt=merge(rt,newnode()); while(m--){ char op[10];int l,r,v,x,y,z,zz,zzz; scanf("%s",op); if(op[0]=='m'){ if(strlen(op)==3){//mul L R v scanf("%d%d%d",&l,&r,&v);++l,++r,v%=P; split(rt,r,x,y); split(x,l-1,x,z); pushup_mul(z,v); rt=merge(merge(x,z),y); } else{//mulx L R scanf("%d%d",&l,&r);++l,++r; split(rt,r+1,x,y); split(x,r,x,z); split(x,r-1,x,zz); t[z].val=(t[z].val+t[zz].val)%P; t[zz].val=0;y=merge(z,y); split(x,l-1,x,z); rt=merge(merge(merge(x,zz),z),y); } } else if(op[0]=='a'){//add L R v scanf("%d%d%d",&l,&r,&v);++l,++r,v%=P; split(rt,r,x,y); split(x,l-1,x,z); pushup_add(z,v); rt=merge(merge(x,z),y); } else{//query v scanf("%d",&v);v%=P; split(rt,t[rt].siz-1,x,z); int ans=t[z].val; while(t[x].siz){ split(x,t[x].siz-1,x,y); ans=(1ll*ans*v%P+t[y].val)%P; z=merge(y,z); } rt=z; printf("%d\n",ans); } } return 0; }