【BZOJ】3323: [Scoi2013]多项式的运算-splay

传送门:bzoj3323
终于把史前巨坑填了(去年10月的坑)!似乎也没那么难码(居然1A了)…


题解

询问次数 ≤ 10 \leq 10 10,直接暴力遍历即可。

多项式最多只有 2 × 1 0 5 2\times 10^5 2×105项,所以先 b u i l d build build出来。

区间加/乘常规操作:维护 f ( x , a , b ) = a x + b f(x,a,b)=ax+b f(x,a,b)=ax+b的操作 ( a , b ) (a,b) (a,b)二元组。

对于右移一位的操作:
删去 R + 1 R+1 R+1并记录其值,加在 R R R上,并在 L L L前插入一个 0 0 0


代码

#include<bits/stdc++.h>
#define mid (l+r>>1)
using namespace std;
typedef long long ll;
const int N=3e5+100,mod=20130426;

int n,cnt,rt,bs,ans,pw[N],lim=2e5;

char cp[100];
inline int init()
{
	scanf("%s",cp);
	if(cp[0]=='m') return strlen(cp)==3?1:3;
	return cp[0]=='a'?2:4;
}

inline int adi(int x,int y){x+=y;return x>=mod?x-mod:x;}

struct eve{
	int a,b;
	eve(int a_=1,int b_=0):a(a_),b(b_){};
	void operator +=(eve ky){a=(ll)a*ky.a%mod,b=adi((ll)ky.a*b%mod,ky.b);}
	bool operator ==(eve &ky)const{return (a==ky.a && b==ky.b);}
	inline int vl(int x){return adi((ll)x*a%mod,b);}
}ori;

namespace Splay{
	#define lc(x) t[x].ch[0]
	#define rc(x) t[x].ch[1]
	#define F(x) t[x].fa

    int stk[N],top;
	struct node{int ch[2],fa,sz,v;eve tg;}t[N];
    
    inline void pu(int x){t[x].sz=t[lc(x)].sz+t[rc(x)].sz+1;}
    inline void pd(int x){
    	if(t[x].tg==ori) return;eve tmp=t[x].tg;t[x].tg=ori;
    	if(lc(x)) t[lc(x)].v=tmp.vl(t[lc(x)].v),t[lc(x)].tg+=tmp;
    	if(rc(x)) t[rc(x)].v=tmp.vl(t[rc(x)].v),t[rc(x)].tg+=tmp;
    }
    
    inline void rot(int x)
    {
    	int y=F(x),z=F(y),dr=(rc(y)==x);
    	t[y].ch[dr]=t[x].ch[dr^1];
    	if(t[y].ch[dr]) F(t[y].ch[dr])=y;
    	F(x)=z;if(z) t[z].ch[(rc(z)==y)]=x;
    	F(y)=x;t[x].ch[dr^1]=y;pu(y);
    }
    
    void splay(int x,int gt)
    {
    	int y,z;if(!gt) rt=x;
    	for(y=x;y;y=F(y)) stk[++top]=y;
    	for(;top;) pd(stk[top--]);
		for(;F(x)^gt;rot(x)){
    	    y=F(x);z=F(y);
    	    if(z^gt) ((rc(y)==x)^(rc(z)==y))?rot(x):rot(y);
    	}
    	pu(x);
    }
    
	void ins(int k){
    	for(int u=rt;;){
    		pd(u);t[u].sz++;
		    if(k<=t[lc(u)].sz){
		    	if(!lc(u)){lc(u)=++cnt;F(cnt)=u;break;}
		    	u=lc(u);
		    }else{
			    k-=(t[lc(u)].sz+1);
			    if(!rc(u)){rc(u)=++cnt;F(cnt)=u;break;}
			    u=rc(u);
			} 
		}
    	t[cnt].sz=1;splay(cnt,0);
    }
    
    inline int kth(int k)
    {
    	for(int u=rt;;){
    		pd(u);
    		if(t[lc(u)].sz+1==k) return u;
    		if(k<=t[lc(u)].sz) u=lc(u);
    		else{k-=(t[lc(u)].sz+1);u=rc(u);}
    	}
    }

}
using namespace Splay;

int build(int l,int r)
{
	if(l>r) return 0;int x=++cnt;
	lc(x)=build(l,mid-1);rc(x)=build(mid+1,r);
	if(lc(x)) F(lc(x))=x;if(rc(x)) F(rc(x))=x;
	pu(x);return x;
}

void modify(int l,int r,eve tmp)
{
	int x=kth(l-1),y=kth(r+1);
	splay(x,0);splay(y,x);pd(y);x=lc(y);
	t[x].v=tmp.vl(t[x].v);t[x].tg+=tmp;
	splay(x,0);
}

void mv(int l,int r)
{
	int val,x=kth(r),y=kth(r+2);
	splay(x,0);splay(y,x);pd(y);
	val=t[lc(y)].v;lc(y)=0;
	pu(y);pu(x);ins(l-1);
	if(val) modify(r+1,r+1,eve(1,val));
}

int cal(int x,int pre)
{
	pd(x);
	if(lc(x)) cal(lc(x),pre);pre+=t[lc(x)].sz;
	if(pre) ans=adi(ans,(ll)t[x].v*pw[pre-1]%mod);
	if(rc(x)) cal(rc(x),pre+1);
}

int main(){
	int i,o,x,y,z;eve tmp;
	rt=build(1,200010);
	for(scanf("%d",&n);n;--n){
		if((o=init())<3){
			scanf("%d%d%d",&x,&y,&z);
			tmp= o==1?eve(z,0):eve(1,z);
			modify(x+2,y+2,tmp);
		}
        else if(o==3){scanf("%d%d",&x,&y);mv(x+2,y+2);}
		else{
		   scanf("%d",&bs);ans=0;pw[0]=1;
		   for(i=1;i<=200010;++i) pw[i]=(ll)pw[i-1]*bs%mod;
		   cal(rt,0);printf("%d\n",ans);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值