BZOJ 3323 多项式的运算
题目描述 Description
某天,mzry1992一边思考着一个项目问题一边在高速公路上骑着摩托车。一个光头踢了他一脚,摩托车损坏,而他也被送进校医院打吊针。现在该项目的截止日期将近,他不得不请你来帮助他完成这个项目。该项目的目的是维护一个动态的关于x的无穷多项式F(x)=
a0
*
x0
+
a1
*
x1
+
a2
*
x2
+…,这个多项式初始时对于所有i有
ai
=0。
操作者可以进行四种操作:
1.将 xL 到 xR 这些项的系数乘上某个定值v
2.将 xL 到 xR 这些项的系数加上某个定值v
3.将 xL 到 xR 这些项乘上x变量
4.将某个定值v代入多项式F(x),并输出代入后多项式的值,之后多项式还原为代入前的状况
经过观察,项目组发现使用者的操作集中在前三种,第四种操作不会出现超过10次。mzry1992负责这个项目的核心代码,你能帮他实现么。
输入描述 Input Description
输入的第一行有一个整数n 代表操作的个数。
接下来n 行,每行一个操作,格式如下:
mul L R v 代表第一种操作
add L R v 代表第二种操作
mulx L R 代表第三种操作
query v 代表第四种操作
输出描述 Output Description
对于每个query 操作,输出对应的答案,结果可能较大,需要模上20130426
样例输入 Sample Input
6
add 0 1 7
query 1
mul 0 1 7
query 2
mulx 0 1
query 3
样例输出 Sample Output
14
147
588
数据范围及提示 Data Size & Hint
对于30%的数据:N≤5000,0≤L≤R≤5000,0≤v≤10^9
另有20%的数据:N≤10^5,0≤L≤R≤10^5,0≤v≤10^9,没有mulx操作
剩下的50%的数据:N≤10^5,0≤L≤R≤10^5,0≤v≤10^9
这道题的题面,emm…,我也不想吐槽什么了
进入正题!
分析:
要求:
维护一个无穷多项式,次数≤100001
需要满足区间加法,区间移动,和查询(次数较少可
O(n)
查询)
这种区间修改问题,可以用看起来可以用线段树,树状数组,Splay,Treap,块状链表骗分,等等
但是是不是都可以用呢?
线段树和树状数组先排除,因为本蒟蒻还不会用线段树和树状数组直接区间移动(欢迎大神来写)
那么Splay和Treap选择那个呢?
当然要祭出 序列之王 Splay 了~
Treap也可以啦,但是本文暂时不讨论
首先介绍一下建图思路:
将中序遍历来代表次数,用key值来保存系数,build二分建图即可(就是快!)
等下就会知道为什么这样建图了
具体操作,具体分析
mul操作&add操作
目的:
1.将
xL
到
xR
这些项的系数乘上某个定值v
2.将
xL
到
xR
这些项的系数加上某个定值v
对于已经入门splay的人来说很easy吧
先将l-1旋至root,将r+1旋至ch[root][1],于是需要操作的区间就是以ch[r][0]为root的子树
我们在ch[r][0]上打上乘法标记和加法标记即可
注意:
下传标记时记得先乘再加
而且下传乘法标记时,不仅需要更新子节点的key值,加法标记也需要一同更新
mulx操作
目的:
将
xL
到
xR
这些项乘上x变量
这个做法就比较巧妙了
我们需要将这个区间的次数都+1,想一想算式的变化,发现:
将这个序列向右平移一位,然后将r和r+1合并即可
那么我们建图时以中序遍历来代表次数的操作就派上用场了
我们找到操作序列中最左侧的一个点(中序遍历时最靠前的点)
为它增加一个key值为0的左儿子,即将l后面的整个序列中序遍历向后推移了一位
我们找到操作序列中最右侧的一个点(中序遍历时最靠后的点)
将其与r+1合并即可,即将r后面的整个序列中序遍历向前推移了一位
这样我们就平移完成了!
query操作
目的:
将某个定值v代入多项式F(x),并输出代入后多项式的值,之后多项式还原为代入前的状况
因为这个操作的次数不会超过10次,直接
O(n)
遍历查询即可
自认为代码可读性比较好~dalao勿喷
Code:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 21000000
#define mod 20130426
#define maxn 400000
ll ch[maxn][2],f[maxn],key[maxn],size[maxn],add[maxn],rid[maxn],num[maxn];
ll root,sz,n,ANS,q;
char str[10];
ll read() {
ll ans=0,flag=1;
char c=getchar();
while( (c>'9' || c<'0') && c!='-' ) c=getchar();
if(c=='-') flag=-1,c=getchar();
while(c>='0' && c<='9') ans=ans*10+c-'0',c=getchar();
return ans*flag;
}
bool get(int x) {return ch[f[x]][1]==x;}
void update(int x) {size[x]=1+size[ch[x][0]]+size[ch[x][1]];}
void clear(int x) {ch[x][0]=ch[x][1]=f[x]=key[x]=size[x]=add[x]=rid[x]=0;}
void pushdown(int x) {
int l=ch[x][0];
int r=ch[x][1];
if(rid[x]!=1) {
if(l) {
key[l]=(key[l]*rid[x])%mod;
add[l]=(add[l]*rid[x])%mod;
rid[l]=(rid[l]*rid[x])%mod;
}
if(r) {
key[r]=(key[r]*rid[x])%mod;
add[r]=(add[r]*rid[x])%mod;
rid[r]=(rid[r]*rid[x])%mod;
}
rid[x]=1;
}
if(add[x]!=0) {
if(l) {
key[l]=(key[l]+add[x])%mod;
add[l]=(add[l]+add[x])%mod;
}
if(r) {
key[r]=(key[r]+add[x])%mod;
add[r]=(add[r]+add[x])%mod;
}
add[x]=0;
}
return ;
}
void rotate(int x) {
int fa=f[x],ffa=f[fa],w=get(x);
pushdown(fa),pushdown(x);
ch[fa][w]=ch[x][w^1],f[ch[fa][w]]=fa;
ch[x][w^1]=fa,f[fa]=x;
f[x]=ffa;
if(ffa)
ch[ffa][ch[ffa][1]==fa]=x;
update(fa),update(x);
return ;
}
void splay(int x,int tar) {
for(int fa;(fa=f[x])!=tar;rotate(x))
if(f[fa]!=tar)
rotate(get(x)==get(fa)?fa:x);
if(!tar)
root=x;
return ;
}
int findx(int x) {
int now=root;
while(1) {
pushdown(now);
if(ch[now][0] && x<=size[ch[now][0]])
now=ch[now][0];
else {
int tmp=(ch[now][0]?size[ch[now][0]]:0)+1;
if(x<=tmp) return now;
x-=tmp;
now=ch[now][1];
}
}
}
int build(int l,int r,int fa) {
if(l>r) return 0;
int mid=(l+r)>>1;
int now=++sz;
f[now]=fa;
rid[now]=1;
size[now]=1;
ch[now][0]=build(l,mid-1,now);
ch[now][1]=build(mid+1,r,now);
update(now);
return now;
}
void MUL() {
int l=read(),r=read();
ll v=read();
l=findx(l+1);
r=findx(r+3);
splay(l,0);
splay(r,l);
key[ch[ch[root][1]][0]]=(key[ch[ch[root][1]][0]]*v)%mod;
add[ch[ch[root][1]][0]]=(add[ch[ch[root][1]][0]]*v)%mod;
rid[ch[ch[root][1]][0]]=(rid[ch[ch[root][1]][0]]*v)%mod;
return ;
}
void ADD() {
int l=read(),r=read();
ll v=read();
l=findx(l+1);
r=findx(r+3);
splay(l,0);
splay(r,l);
key[ch[ch[root][1]][0]]=(key[ch[ch[root][1]][0]]+v)%mod;
add[ch[ch[root][1]][0]]=(add[ch[ch[root][1]][0]]+v)%mod;
return ;
}
void MULX() {
int l=read(),r=read();
l=findx(l+1);
r=findx(r+3);
splay(l,0);
splay(r,l);
pushdown(l),pushdown(r);
int now=r;
while(ch[now][0])
pushdown(now),now=ch[now][0];
pushdown(now);
ch[now][0]=++sz;
clear(sz);
f[sz]=now;
rid[sz]=1;
size[sz]=1;
while(now)
update(now),now=f[now];
now=ch[r][0];
while(ch[now][1])
pushdown(now),now=ch[now][1];
pushdown(now);
key[r]=(key[r]+key[now])%mod;
int fa=f[now],w=get(now);
if(ch[now][0]) {
ch[fa][w]=ch[now][0];
f[ch[fa][w]]=fa;
}
else
ch[fa][w]=0;
clear(now);
while(fa)
update(fa),fa=f[fa];
return ;
}
void print(int x) {
pushdown(x);
if(ch[x][0])
print(ch[x][0]);
if(q!=-1)
ANS=(ANS+(num[q]*key[x])%mod)%mod;
q++;
if(ch[x][1])
print(ch[x][1]);
return ;
}
void QUERY() {
ll v=read();
ANS=0,q=-1;
if(!v) {
puts("0");
return ;
}
num[0]=1;
for(int i=1;i<=100001;i++)
num[i]=(num[i-1]*v)%mod;
print(root);
printf("%lld\n",ANS);
return ;
}
int main() {
n=read();
root=build(1,100100,0);
while(n--) {
scanf("%s",str);
if(str[0]=='m' && strlen(str)==3)
MUL();
else if(str[0]=='a')
ADD();
else if(str[0]=='m' && strlen(str)==4)
MULX();
else if(str[0]=='q')
QUERY();
}
return 0;
}
PS:
话说你知道2014年四川省选是什么时候么?
答案就在博客中哦~