cunzai_zsy0531

关注我

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;
}
posted @ 2022-05-19 16:37  cunzai_zsy0531  阅读(28)  评论(0编辑  收藏  举报