bzoj3323: [Scoi2013]多项式的运算【无旋treap】

Description

某天,mzry1992 一边思考着一个项目问题一边在高速公路上骑着摩托车。一个光头踢了他一脚,摩托车损坏,而他也被送进校医院打吊针。现在该项目的截止日期将近,他不得不请你来帮助他完成这个项目。该项目的目的是维护一个动态的关于x 的无穷多项式F(x) = a0 * x^0 + a1 * x^1 + a2 * x^2 + … ,这个多项式初始时对于所有i有ai = 0。
操作者可以进行四种操作:
1. 将x^L 到x^R 这些项的系数乘上某个定值v
2. 将x^L 到x^R 这些项的系数加上某个定值v

  1. 将x^L 到x^R 这些项乘上x变量
  2. 将某个定值v代入多项式F(x),并输出代入后多项式的值,之后多项式还原为代入前的状况
    经过观察,项目组发现使用者的操作集中在前三种,第四种操作不会出现超过10次。mzry1992 负责这个项目的核心代码,你能帮他实现么。
Input

输入的第一行有一个整数n 代表操作的个数。
接下来n 行,每行一个操作,格式如下:
mul L R v 代表第一种操作
add L R v 代表第二种操作
mulx L R 代表第三种操作
query v 代表第四种操作

对于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

Output

对于每个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

Hint

操作一之后,多项式为F(x) = 7x + 7。

操作三之后,多项式为F(x) = 49x + 49。

操作五之后,多项式为F(x) = 49x^2 + 49x。

解题思路:

这题无旋treap好些一点,不过有点卡。
主要是mulx操作如何处理:将(r,r)的系数加到(r+1,r+1)上,再在(l,r-1)左边插入一个系数为0的节点即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=100005,mod=20130426;
int n,m,tot,root,fa[N],pri[N],son[N][2],size[N];
int ans,x,curx,a[N],add[N],mul[N];char s[5];

inline int upt(int u)
{
    size[u]=size[son[u][0]]+size[son[u][1]]+1;
    return u;
}

void pushdown(int u)
{
    int l=son[u][0],r=son[u][1],k=mul[u],b=add[u];
    if(l)a[l]=(1ll*a[l]*k+b)%mod,add[l]=(1ll*add[l]*k+b)%mod,mul[l]=1ll*mul[l]*k%mod;
    if(r)a[r]=(1ll*a[r]*k+b)%mod,add[r]=(1ll*add[r]*k+b)%mod,mul[r]=1ll*mul[r]*k%mod;
    mul[u]=1,add[u]=0;
}
int merge(int u,int v)
{
    if(!u)return upt(v);
    if(!v)return upt(u);
    if(pri[u]<pri[v])
    {
        pushdown(u),son[u][1]=merge(son[u][1],v);
        return upt(u);
    }
    else
    {
        pushdown(v),son[v][0]=merge(u,son[v][0]);
        return upt(v);
    }
}
void split(int u,int kth,int &L,int &R)
{
    if(!u){L=R=0;return;}
    pushdown(u);
    if(size[son[u][0]]<kth)
    {
        split(son[u][1],kth-size[son[u][0]]-1,L,R);
        son[u][1]=L,L=u,upt(u);
    }
    else
    {
        split(son[u][0],kth,L,R);
        son[u][0]=R,R=u,upt(u);
    }
}
void Add(int l,int r,int b)
{
    int L=0,R=0,p=0,q=0;
    split(root,l-1,L,R);
    split(R,r-l+1,p,q);
    a[p]=(a[p]+b)%mod,add[p]=(add[p]+b)%mod;
    root=merge(merge(L,p),q);
}
void Mul(int l,int r,int k)
{
    int L=0,R=0,p=0,q=0;
    split(root,l-1,L,R);
    split(R,r-l+1,p,q);
    a[p]=1ll*a[p]*k%mod,add[p]=1ll*add[p]*k%mod,mul[p]=1ll*mul[p]*k%mod;
    root=merge(merge(L,p),q);
}
void Mulx(int l,int r)
{
    int L=0,R=0,p=0,q=0,w=0,x=0,y=0,z=0;
    split(root,l-1,L,R),split(R,r+1-l+1,p,q),split(p,r-l+1,x,y);
    split(x,r-1-l+1,w,z);
    a[y]=(a[y]+a[z])%mod,a[z]=0;
    root=merge(merge(merge(merge(L,z),w),y),q);
}
int query(int u)
{
    pushdown(u);
    if(son[u][0])query(son[u][0]);
    ans=(1ll*a[u]*curx+ans)%mod;curx=1ll*curx*x%mod;
    if(son[u][1])query(son[u][1]);
}
int main()
{
    //freopen("lx.in","r",stdin);
    //freopen("lx.out","w",stdout);
    m=getint();n=100001;int l,r;
    for(int i=0;i<=n;i++)
    {
        a[++tot]=0,pri[tot]=rand(),mul[tot]=1;
        root=merge(root,tot);
    }
    while(m--)
    {
        scanf("%s",s);
        if(s[0]=='a')l=getint()+1,r=getint()+1,Add(l,r,getint());
        else if(s[0]=='q')ans=0,curx=1,x=getint(),query(root),printf("%d\n",ans);
        else if(s[3]=='x')l=getint()+1,r=getint()+1,Mulx(l,r);
        else l=getint()+1,r=getint()+1,Mul(l,r,getint());
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值