bzoj3323: [Scoi2013]多项式的运算 splay

对于多项式的每一项 我们可以建一个节点记录其系数。然后这题就成了裸地模板题。

求值操作直接o(n)搞。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define maxn 1000000+100
#define maxm 100000+100
#define INF 0x3f3f3f3f
#define mod 20130426
typedef long long sint;
inline int getint()
{
    int res=0,f=1;char c;
    while(c=getchar(),c<'0'||c>'9'){if(c=='-')f=-1;}
    res=c-'0';
    while(c=getchar(),c>='0'&&c<='9')res=res*10+c-'0';
    return res*f;
}
int tr[maxn][2],fa[maxn],root,n,m;
sint v[maxn],t[maxn][2],ans,bas;
int siz[maxn],tot,t1,t2;
inline void pushup(int rt)
{
    siz[rt]=siz[tr[rt][0]]+siz[tr[rt][1]]+1;
}
inline void update(int x,sint xx,sint yy)
{
    if(!x) return;
    v[x]=(v[x]*yy+xx)%mod;
    ((t[x][0]*=yy)+=xx)%=mod;
    (t[x][1]*=yy)%=mod;
}
inline void pushdown(int x)
{
    if(!x)return;
    if(!t[x][0]&&t[x][1]==1)return;
    update(tr[x][0],t[x][0],t[x][1]);
    update(tr[x][1],t[x][0],t[x][1]);
    t[x][0]=0;t[x][1]=1;
}
inline void rotate(int x,int &rt)
{
    int l,r,z,y;
    y=fa[x];z=fa[y];
    if(x==tr[y][0]) l=0;
    else l=1;r=1^l;
    if(rt==y) rt=x;
    else
    {
        if(tr[z][0]==y) tr[z][0]=x;
        else tr[z][1]=x;
    }
    fa[x]=z;fa[y]=x;fa[tr[x][r]]=y;
    tr[y][l]=tr[x][r];tr[x][r]=y;
    pushup(y);pushup(x);
}
inline void build(int l,int r,int f)
{
    if(l>r)return;
    int mid=(l+r)>>1;
    fa[mid]=f;tr[f][mid>f]=mid;
    siz[mid]=1;t[mid][0]=0;t[mid][1]=1;
    if(l==r)return;
    build(l,mid-1,mid);build(mid+1,r,mid);
    pushup(mid);
}
inline void splay(int x,int &rt)
{
    int y,z;
    while(x!=rt)
    {
        y=fa[x];z=fa[y];
        if(y!=rt)
        {
            if((tr[y][0]==x)^(tr[z][0]==y)) rotate(x,rt);
            else rotate(y,rt);
        }
        rotate(x,rt);
    }
}
int select(int now,int rk)
{
    pushdown(now);
    int l=tr[now][0],r=tr[now][1];
    int rak=siz[l]+1;
    if(rak==rk) return now;
    if(rak>rk) return select(l,rk);
    else return select(r,rk-rak);
}
 
inline void calc(int x)
{
     if(!x)return;
     pushdown(x);
     calc(tr[x][1]);
     if(x!=1)ans=(ans*bas+v[x])%mod;
     calc(tr[x][0]);
}
inline void split(int l,int r)
{
    t1=select(root,l);t2=select(root,r);
    splay(t1,root);splay(t2,tr[t1][1]);
}
int main()
{
    build(1,maxm,0);
    tot=maxm;root=(1+maxm)>>1;
    int q=getint();char ch[maxn];
    while(q--)
    {
        scanf("%s",ch);
        if(ch[0]=='q')
        {
            ans=0;bas=getint()%mod;
            calc(root);
            cout<<ans<<endl;
        }
        else
        {
             int x=getint()+1,y=getint()+1;
             if(ch[3]=='x')
             {
                 split(y,y+2);
                 pushdown(t1),pushdown(t2);
                 v[t2]+=v[tr[t2][0]];
                 fa[tr[t2][0]]=tr[t2][0]=0;
                 pushup(t2);pushup(t1);
 
                 split(x,x+1);
                 tr[t2][0]=++tot;siz[tot]=1;
                 v[tot]=0;fa[tot]=t2;t[tot][1]=1;
                 pushup(t2);pushup(t1);
             }
             else if(ch[0]=='m')
             {
                split(x,y+2);
                sint xx=0,yy=getint()%mod;
                update(tr[t2][0],xx,yy);
                pushup(t2);pushup(t1);
             }
             else
             {
                split(x,y+2);
                int xx=getint()%mod,yy=1;
                update(tr[t2][0],xx,yy);
                pushup(t2);pushup(t1);
             }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值