BZOJ1500维修数列Splay

不得不说这题目真的猥琐,写一个小时调一晚上加一上午,还被卡常了。
这里不放题解,主要来总结一下Splay区间修改比较猥琐的地方。
一 、查找第k大的时候一定要记得push_down;
二、有改值标记的题目push_down一定要写成改值的push_down,今天我才知道我以前写的线段树都是jg,全是错的标记方式。
三、注意一下边界问题和Splay函数里的push_down和update操作。
四、注意update的常数…
代码

#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<string>
#include<cassert>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<climits>
#define X first
#define Y second
#define DB double
#define MP make_pair
#define LL long long
#define pb push_back
#define sqr(_) ((_)*(_))
#define INF 0x3f3f3f3f
#define pii pair<int,int>
#define pdd pair<DB,DB>
#define ull unsigned LL
#define lc son[now][0]
#define rc son[now][1]
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
const int MAXN=600010;
int n,m,st[MAXN],top=0,a[MAXN];
char s[20]={};
void Read(int& x)
{
    x=0;int flag=0,sgn=1;char c;
    while(c=getchar())
    {
        if(c=='-')sgn=-1;
        else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
        else if(flag)break;
    }
    x*=sgn;
}
inline int max(int x,int y)
{
    return x>y?x:y;
}
struct splay_Tree{
    int size[MAXN],v[MAXN],sum[MAXN],lm[MAXN],mx[MAXN],rm[MAXN];
    int son[MAXN][2],root,cnt,fa[MAXN],rev[MAXN],cov[MAXN];
    splay_Tree()
    {
        root=cnt=0;
        memset(fa,0,sizeof(fa));
        memset(cov,INF,sizeof(cov));
        memset(size,0,sizeof(size));
        memset(sum,0,sizeof(sum));
        memset(son,0,sizeof(son));
        memset(lm,-INF,sizeof(lm));
        memset(mx,-INF,sizeof(mx));
        memset(rm,-INF,sizeof(rm));
        fa[2]=1;son[1][1]=2;root=1;
        lm[1]=rm[1]=mx[1]=lm[2]=mx[2]=rm[2]=0;
        lm[0]=mx[0]=rm[0]=-INF;
        size[2]=1;size[1]=2;
    }
    int build(int b,int val,int d)
    {
        int New=st[top];top--;
        fa[New]=b;
        son[b][d]=New;
        cov[New]=INF;
        rev[New]=son[New][0]=son[New][1]=0;
        v[New]=sum[New]=mx[New]=lm[New]=rm[New]=val;
        size[New]=1;
        return New;
    }
    void update(int now)
    {
        if(!now)return;
        size[now]=size[lc]+size[rc]+1;
        sum[now]=sum[lc]+sum[rc]+v[now];
        mx[now] = max(0,rm[lc])+v[now]+max(0,lm[rc]);
        mx[now] = max(mx[now],max(mx[lc],mx[rc]));
        lm[now] = max(lm[lc],sum[lc]+v[now]+max(0,lm[rc]));
        rm[now] = max(rm[rc],sum[rc]+v[now]+max(0,rm[lc]));
    }
    void update_same(int now,int c)
    {
        if(!now)return;
        cov[now]=c;
        v[now]=c;
        sum[now]=size[now]*c;
        mx[now]=max(sum[now],c);
        lm[now]=max(sum[now],c);
        rm[now]=max(sum[now],c);
    }
    void update_rev(int now)
    {
        if(!now)return;
        rev[now]^=1;
        std::swap(lc,rc);
        std::swap(lm[now],rm[now]);
    }
    void push_down(int now)
    {
        if(!now)return;
        if(rev[now])
        {
            update_rev(lc);
            update_rev(rc);
            rev[now]=0;
        }
        if(cov[now]!=INF)
        {
            update_same(son[now][0],cov[now]);
            update_same(son[now][1],cov[now]);
            cov[now]=INF;
        }
    }
    void rotate(int x)
    {
        int y=fa[x],d=son[y][1]==x?1:0;
        push_down(y);
        push_down(x);
        if(fa[y])
            son[fa[y]][son[fa[y]][1]==y]=x;
        fa[x]=fa[y];
        fa[y]=x;
        if(son[x][d^1])
            fa[son[x][d^1]]=y;
        son[y][d]=son[x][d^1];
        son[x][d^1]=y;
        update(y);
    }
    void splay(int x,int f)
    {
        push_down(x);
        while(fa[x]!=f)
        {
            int y=fa[x];
            if(fa[y]==f)
            {
                rotate(x);
                break;
            }
            if((son[fa[y]][1]==y)^(son[y][1]==x))
            {
                rotate(x);
                rotate(x);
            }
            else 
            {
                rotate(y);
                rotate(x);
            }
        }
        if(f==0)
            root=x;
        update(x);
    }
    int find(int now,int k)
    {
        push_down(now);
        if(size[lc]+1>k)
            find(lc,k);
        else if(size[lc]+1==k)
            return now;
        else
            find(rc,k-size[lc]-1);
    }
    void Insert(int now,int val)
    {
        int a=find(root,now+1),
            b=find(root,now+2);
        splay(a,0);
        splay(b,root);
        build(b,val,0);
        update(b);
        update(a);
    }
    void recy(int now)
    {
        if(!now)return;
        st[++top]=(now);
        recy(lc);
        recy(rc);
    }
    void del(int now,int tot)
    {
        int a=find(root,now),
            b=find(root,now+tot+1);
        splay(a,0);
        splay(b,root);
        int s=son[b][0];
        fa[s]=0;son[b][0]=0;
        recy(s);
    }
    void mod(int now,int tot,int c)
    {
        int a=find(root,now),
            b=find(root,now+tot+1);
        splay(a,0);
        splay(b,root);
        update_same(son[b][0],c);
        update(b);
        update(a);
    }
    void Rev(int now,int tot)
    {
        int a=find(root,now),
            b=find(root,now+tot+1);
        splay(a,0);
        splay(b,root);
        update_rev(son[b][0]);
        update(b);
        update(a);
    }
    void Sum(int now,int tot)
    {
        //assert(now!=0);
        int a=find(root,now),
            b=find(root,now+tot+1);
        //DEBUG("%d\n",mx[root]);
        splay(a,0);
        //DEBUG("%d\n",mx[root]);
        splay(b,root);
        //DEBUG("%d\n",mx[root]);
        printf("%d\n",sum[son[b][0]]);
    }
    void Max()
    {
        splay(1,0);
        splay(2,1);
        printf("%d\n",mx[son[2][0]]);
    }
    void init(int l,int r,int f,int d)
    {
        if(l>r)return;
        int mid=(l+r)>>1;
        int now=build(f,a[mid],d);
        init(l,mid-1,now,0);
        init(mid+1,r,now,1);
        update(now);
    }
}T;
int main()
{
#ifndef ONLINE_JUDGE
    freopen("mend.in","r",stdin);
    freopen("mend.out","w",stdout);
#endif
    std::cin>>n>>m;
    for(int i=600000;i>=1;i--)
        st[++top]=i;
    top-=2;
    int tot=0;
    for(int i=1;i<=n;i++)
    {
        Read(a[i]);
    }
    T.init(1,n,2,0);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",s);
        //DEBUG("%d %s\n",i,s);
        if(s[0]=='G')
        {
            int a,b;
            Read(a);Read(b);
            T.Sum(a,b);
        }
        else if(s[0]=='M'&&s[2]=='X')
            T.Max();
        else if(s[0]=='I')
        {
            tot=0;
            int a,b,c;
            Read(a);Read(b);
            for(int i=1;i<=b;i++)
            {
                Read(c);
                T.Insert(a+tot,c);
                tot++;
            }
        }
        else if(s[2]=='K')
        {
            int a,b,c;
            Read(a);Read(b);Read(c);
            T.mod(a,b,c);
        }
        else if(s[0]=='R')
        {
            int a,b;
            Read(a);Read(b);
            T.Rev(a,b);
        }
        else 
        {
            int a,b;
            Read(a);Read(b);
            T.del(a,b);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值