P3278 [SCOI2013]多项式的运算 题解
前两个操作放过来看似是一道线段树题,但是发现线段树无法维护第三个操作。考虑使用平衡树(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;
}