BZOJ3323 SCOI2013 多项式的运算
AC链接:传送门
题目分析:
一道比较难写的splay模板题,可以看出scoi与hnoi相比,思维难度略低。
首先观察操作4,题目限制操作4的个数不会超过10个,但是经过分析可以发现题目中的无穷多项式是唬人的,最多的一项只会到达2*105级别,那么每一次用O(n)可以计算,最多十次仅O(10n),因此这一部分可以暴力解决。
忽略操作3,那么把多项式的每一项看作splay上的第i个点,预先建好n个点会使问题变简单许多,加法和乘法可以用标记解决,那么在没有操作3的情况下有一个O(nlogn)的splay做法。
加入操作3,操作3在[l,r]上乘以x,仅仅只会平移一项,那么我们将这一步拆分成下面独立的几步:
1.找到第l项,第r项与第r+1项所对应的结点的值。
2.将第r+1项所对应的结点的data加上第r项所对应的结点的data。
3.旋转,提取区间[l,r]。
4.删除第r项对应的结点。
5.给区间[l,r]对应的结点打上项数+1的标记,这时候我们发现,它们在splay中的相对位置没有改变!因此这个做法是成立的。
6.补充第l项对应的结点,用删除的结点补充即可。
题目难点:
这道题的难点在于代码的难写程度。维护三个标记是其一大恶心之处,但是其中的项+1标记与另外两个标记是独立的。
另外两个标记的维护与洛谷的某道线段树练习相似。
我们先让有乘法标记时乘法优于加法处理,那么当每个乘法标记被打上的时候,我们需要下放结点上的加法标记。但是打加法标记时不需要下放乘法标记,这样标记下传是O(1)的。
代码如下:
1 #include<bits/stdc++.h> 2 #define L (t[now].ch[0]) 3 #define R (t[now].ch[1]) 4 using namespace std; 5 6 typedef long long ll; 7 8 const ll maxn = 300010; 9 const ll mod = 20130426; 10 struct node{ 11 ll data; 12 ll num,ch[2],fa; 13 ll lznum,lzmul,lzad; 14 node(){lzmul=1;data=num=ch[0]=ch[1]=fa=lznum=lzad=0;} 15 }t[maxn]; 16 ll n,root=1,nb=1; 17 18 void r0(ll now,ll dr){ // 0 left ,1 right 19 ll son = t[now].ch[dr],fa = t[now].fa,gf = t[fa].fa; 20 t[son].fa = fa; t[fa].ch[dr^1] = son; 21 t[now].ch[dr] = fa; t[fa].fa = now; t[now].fa = gf; 22 if(t[gf].ch[0] == fa && gf != 0){t[gf].ch[0] = now;return;} 23 if(t[gf].ch[1] == fa && gf != 0){t[gf].ch[1] = now;return;} 24 root = now; 25 } 26 27 void push_down1(ll now){ 28 t[now].num+=t[now].lznum; 29 t[L].lznum+=t[now].lznum; 30 t[R].lznum+=t[now].lznum; 31 t[now].lznum = 0; 32 } 33 34 void push_down2(ll now){ 35 t[now].data *= t[now].lzmul; t[now].data %= mod; 36 t[L].lzmul*=t[now].lzmul; t[L].lzmul %= mod; 37 t[R].lzmul*=t[now].lzmul; t[R].lzmul %= mod; 38 t[L].lzad*=t[now].lzmul; t[L].lzad %= mod; 39 t[R].lzad*=t[now].lzmul; t[R].lzad %= mod; 40 t[now].lzmul = 1; 41 } 42 43 void push_down3(ll now){ 44 t[now].data += t[now].lzad; t[now].data %= mod; 45 t[L].lzad += t[now].lzad; t[L].lzad %= mod; 46 t[R].lzad += t[now].lzad; t[R].lzad %= mod; 47 t[now].lzad = 0; 48 } 49 50 ll fdnum(ll wt,ll now){ 51 if(t[now].lznum)push_down1(now); 52 if(t[now].lzmul != 1)push_down2(now); 53 if(t[now].lzad)push_down3(now); 54 if(t[now].num == wt) return now; 55 if(t[now].num > wt) return fdnum(wt,L); 56 else return fdnum(wt,R); 57 } 58 59 stack <ll> sta; 60 void splay(ll now,ll fwd = 0){ 61 ll fnow = now; 62 while(fnow != fwd) sta.push(fnow),fnow=t[fnow].fa; 63 while(!sta.empty()){ 64 ll k=sta.top();sta.pop(); 65 if(t[k].lznum)push_down1(k); 66 if(t[k].lzmul != 1)push_down2(k); 67 if(t[k].lzad)push_down3(k); 68 } 69 if(now == fwd)return; 70 while(t[now].fa != fwd){ 71 if(t[t[now].fa].fa == fwd){ 72 if(t[t[now].fa].ch[1] == now) r0(now,0); 73 else r0(now,1); 74 }else{ 75 ll f = t[now].fa; 76 if(t[f].ch[0] == now){ 77 if(t[t[f].fa].ch[0] == f) r0(f,1),r0(now,1); 78 else r0(now,1),r0(now,0); 79 }else{ 80 if(t[t[f].fa].ch[0] == f) r0(now,0),r0(now,1); 81 else r0(f,0),r0(now,0); 82 } 83 } 84 } 85 } 86 87 void insert(ll now,ll dt,ll wtis){ 88 while(true){ 89 if(t[now].lznum) push_down1(now); 90 if(t[now].lzmul!=1) push_down2(now); 91 if(t[now].lzad) push_down3(now); 92 if(t[now].num > dt){ 93 if(t[now].ch[0])now = t[now].ch[0]; 94 else{t[now].ch[0]=wtis;t[wtis].fa = now;splay(now);break;} 95 }else{ 96 if(t[now].ch[1])now = t[now].ch[1]; 97 else{t[now].ch[1]=wtis;t[wtis].fa = now;splay(now);break;} 98 } 99 } 100 } 101 102 void mul(){ 103 ll a,b;ll v; scanf("%lld%lld%lld",&a,&b,&v);v %= mod; 104 b = fdnum(b+1,root);splay(b); 105 if(a == 0){ 106 push_down2(t[root].ch[0]); 107 push_down3(t[root].ch[0]); 108 t[t[root].ch[0]].lzmul = v; 109 } else{ 110 a = fdnum(a-1,root);splay(a,root); 111 ll now = t[root].ch[0]; 112 push_down2(R); push_down3(R); 113 t[R].lzmul = v;t[R].lzmul %= mod; 114 } 115 } 116 117 void add(){ 118 ll a,b;ll v; scanf("%lld%lld%lld",&a,&b,&v);v %= mod; 119 b = fdnum(b+1,root);splay(b); 120 if(a == 0) t[t[root].ch[0]].lzad += v,t[t[root].ch[0]].lzad %= mod; 121 else{ 122 a=fdnum(a-1,root);splay(a,root); 123 ll now = t[root].ch[0];t[R].lzad += v;t[R].lzad %= mod; 124 } 125 } 126 127 void mov(){ 128 ll a,b; scanf("%lld%lld",&a,&b); 129 ll za = a,zb = b; 130 splay(fdnum(b,root)); 131 ll nbb = fdnum(b+1,root); 132 splay(nbb,root); 133 t[t[t[root].ch[1]].ch[1]].fa = root; 134 t[root].ch[1] = t[t[root].ch[1]].ch[1]; 135 t[root].data += t[nbb].data; t[root].data %= mod; 136 t[nbb].ch[0] = t[nbb].ch[1] = t[nbb].fa = 0; 137 t[nbb].num = a; t[nbb].data = 0; t[nbb].lznum = t[nbb].lzad = 0; 138 t[nbb].lzmul = 1; 139 splay(fdnum(b+2,root)); 140 if(a == 0){ 141 t[t[root].ch[0]].lznum++; 142 }else{ 143 splay(fdnum(a-1,root),root); 144 t[t[t[root].ch[0]].ch[1]].lznum++; 145 } 146 insert(root,a,nbb); 147 } 148 149 queue <ll> q; 150 ll sm[maxn]; 151 int ddd[maxn]; 152 void force(){ 153 ll v; scanf("%lld",&v);v %= mod;sm[0] = 1; 154 for(int i=1;i<=2e5;i++) sm[i] = sm[i-1]*v,sm[i] %= mod; 155 q.push(root); 156 ll ans = 0; 157 while(!q.empty()){ 158 ll k = q.front();q.pop(); 159 if(t[k].lznum) push_down1(k); 160 if(t[k].lzmul!=1) push_down2(k); 161 if(t[k].lzad) push_down3(k); 162 //ddd[t[k].num] = t[k].data; 163 ans += sm[t[k].num]*t[k].data; 164 ans %= mod; 165 if(t[k].ch[0] != 0) q.push(t[k].ch[0]); 166 if(t[k].ch[1] != 0) q.push(t[k].ch[1]); 167 } 168 //for(int i=0;i<=10;i++) cout<<ddd[i]<<" "; 169 printf("%lld\n",ans); 170 } 171 172 void read(){ 173 scanf("%lld",&n); 174 for(int i=1;i<=n;i++){ 175 char C = getchar(),P=getchar(); 176 while(P != ' '){C = P;P=getchar();} 177 switch(C){ 178 case 'l':{mul();break;} 179 case 'd':{add();break;} 180 case 'x':{mov();break;} 181 default:{force();} 182 } 183 } 184 } 185 186 int main(){ 187 for(int i=1;i<=(int)2e5+10;i++) {t[++nb].num = i;insert(root,i,nb);} 188 read(); 189 return 0; 190 }