伸展树最重口味题 维修数列

链接 : http://www.lydsy.com/JudgeOnline/problem.php?id=1500

如果都做到这题了,就不多说了

有很多的注意点,代码中有注释

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf = ~0u>>2;
#define L ch[x][0]
#define R ch[x][1]
#define KT (ch[ ch[rt][1] ][0])
const int maxn = 500010;
struct SplayTree {
    int sz[maxn];
    int ch[maxn][2];
    int pre[maxn];
    int rt,top,top2;
    int que[maxn],ss[maxn];
    inline int max(int a,int b) {
        return a>b?a:b;
    }
    inline void down(int x){
        if(!x) return ;
        if(flip[x]) {
            flip[ L ] ^= 1;
            flip[ R ] ^= 1;
            swap(L,R);
            swap(ls[x],rs[x]);
            flip[x] = false ;
        }
        if(same[x]) {//注意防止将0节点赋值
            if(L) same[ L ]  = 1;
            if(R) same[ R ]  = 1;
            if(L)val[ L ]  = val[x];
            if(R)val[ R ]  = val[x];
            if(L)sum[ L ]  = val[x] * sz[ L ];
            if(R)sum[ R ]  = val[x] * sz[ R ];
            if(L)mx_sum[L] = ls [ L ] = rs[ L ] = max(val[x],sum[ L ]);
            if(R)mx_sum[R] = ls [ R ]  = rs[ R ] = max(val[x],sum[ R ]);
            same[x] = false ;
        }
    }
    inline void up(int x){
        if(!x) return;
		if(L) down(L);
		if(R) down(R);//关键所在,儿子节点的信息必须先down下去,不然有可能得到的mx_sum不是真实的
        sz[x] = 1 + sz[ L ] + sz[ R ];
        sum[x] = val[x] + sum[L] + sum[R];
        ls[x] = max( ls[L] , sum[L] + val[x] + max(ls[R],0));
        rs[x] = max( rs[R] , sum[R] + val[x] + max(rs[L],0));
        mx_sum[x] = max(rs[L],0) + val[x] + max(ls[R],0);
        mx_sum[x] = max(mx_sum[x],max(mx_sum[L],mx_sum[R]));
    }
    inline void Rotate(int x,int f){
        int y=pre[x];
        down(y);
        down(x);
        ch[y][!f] = ch[x][f];
        pre[ ch[x][f] ] = y;
        pre[x] = pre[y];
        if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x;
        ch[x][f] = y;
        pre[y] = x;
        up(y);
    }
    inline void Splay(int x,int goal){//将x旋转到goal的下面
        down(x);//防止pre[x]就是目标点,下面的循环就进不去了,x的信息就传不下去了
        while(pre[x] != goal){
            down(pre[pre[x]]); down(pre[x]);down(x);//在旋转之前需要先下传标记,因为节点的位置可能会发生改变
            if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x);
            else   {
                int y=pre[x],z=pre[y];
                int f = (ch[z][0]==y);
                if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f);
                else Rotate(y,f),Rotate(x,f);
            }
        }
        up(x);
        if(goal==0) rt=x;
    }                
    inline void RTO(int k,int goal){//将第k位数旋转到goal的下面
        int x=rt;
        down(x);
        while(sz[ L ]+1 != k) {
            if(k < sz[ L ] + 1 ) x=L;
            else {
                k-=(sz[ L ]+1);
                x = R;
            }
            down(x);
        }
        Splay(x,goal);
    }
    inline void Newnode(int &x,int c,int f){
        if(top2) x = ss[--top2];
        else     x = ++top;   
        L = R = 0; pre[x]=f;
        sz[x] = 1; 

        val[x] = c;  sum[x] = c;
        flip[x] = same[x] = false;
        ls[x] = rs[x] = mx_sum[x] = c;
    }
    inline void build(int &x,int l,int r,int f){
        if(l>r) return ;
        int m=l+r>>1;
        Newnode(x,num[m],f);
        build(L , l , m-1 , x);
        build(R , m+1 , r , x);
        pre[x]=f;
        up(x);
    }
    inline void debug(){
        vist(rt);
		puts("");
    }
    inline void init(int n){
        ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
        rt=top=top2=0; 
        flip[0]=false;   val[0]=0; sum[0]=0; same[0] = false;
        ls[0] = rs[0] = mx_sum[0] = -inf;
        for(int i = 1 ; i <= n ; i++)  scanf("%d" , &num[i]);
        Newnode(rt,-inf,0);
        Newnode(ch[rt][1],-inf,rt);
        sz[rt]=2;
        build(KT,1,n,ch[rt][1]);
        up(ch[rt][1]);
        up(rt);
    }
    inline void erase(int x) {//把以x为祖先结点删掉放进内存池,回收内存
        int father = pre[x];
        int head = 0 , tail = 0;
        for (que[tail++] = x ; head < tail ; head ++) {
            ss[top2 ++] = que[head];
            if(ch[ que[head] ][0]) que[tail++] = ch[ que[head] ][0];
            if(ch[ que[head] ][1]) que[tail++] = ch[ que[head] ][1];
        }
        ch[ father ][ ch[father][1] == x ] = 0;
        up(father);
    }
    void vist(int x){
        if(x){
            printf("结点%2d : 左儿子  %2d   右儿子  %2d    val : %5d  mxsum : %5d    flip :  %5d  same : %d\n",x,
            L,R,val[x],mx_sum[x],flip[x],same[x]);
            vist(L);
            vist(R);
        }
    }
    inline void GET_SUM() {
         scanf("%d%d",&pos,&tot);
         int l=pos,r=pos+tot-1;
         RTO(l,0);
         RTO(r+2,rt);
         printf("%d\n",sum[KT]);
    }
    inline void DELETE()  {
         scanf("%d%d",&pos,&tot);
         int l=pos,r=tot+pos-1;
         RTO(l,0);
         RTO(r+2,rt);
         erase(KT);
         KT=0;
         up(ch[rt][1]);
         up(rt);
    }
    inline void INSERT()  {
        scanf("%d%d",&pos,&tot);
        for(int i=1;i<=tot;i++)    scanf("%d",&num[i]);
        RTO(pos+1,0);
        RTO(pos+2,rt);
        build(KT,1,tot,ch[rt][1]);
        up(ch[rt][1]);    up(rt);
    }
    inline void MAKE_SAME() {
        int c;
        scanf("%d%d%d",&pos,&tot,&c);
        int l=pos,r=pos+tot-1;
        RTO(l,0);
        RTO(r+2,rt);
        same[KT] = true;
        val[KT] = c;
        sum[KT] = sz[KT] * c;
        mx_sum[KT] = max( c , sum[KT] );
        ls[KT] = max(c , sum[KT]);
        rs[KT] = max(c , sum[KT]);
        up(ch[rt][1]);
        up(rt);
    }
    void print(int x) {
        if(x) {
            down(x);
            print(L);
            if(val[x]>-10000) {
                if(flag) printf(" ");
                printf("%d",val[x]);
                flag=1;
            }
            print(R);
        }
    }
    inline void OUT() {
        flag=0;
        print(rt);
        printf("\n");
    }
    inline void REVERSE() {
        scanf("%d%d",&pos,&tot);
        int l=pos,r=pos+tot-1;
        RTO(l,0);
        RTO(r+2,rt);
        flip[KT]^=1;
    }
	inline void MAX_SUM() {
         RTO(1,0) ;
         RTO(sz[rt],rt);
         printf("%d\n",mx_sum[KT]);
    }
    int flag;
    int pos,tot;
    bool flip[maxn];
    int val[maxn];
    int num[maxn];
    int sum[maxn];//求和
    bool same[maxn];//统一修改为一个数
    int ls[maxn];//最大前缀和
    int rs[maxn];//最大后缀和
    int mx_sum[maxn];//最大子列和
}spt;
int main()
{
    int n,m,pos,tot;
    scanf("%d%d",&n,&m);
    spt.init(n);
    char op[50];
    while(m--) {
        scanf("%s",op);
        if(strcmp(op,"GET-SUM") == 0) {
            spt.GET_SUM();
        }  else if(strcmp(op,"MAX-SUM") == 0) {
            spt.MAX_SUM();
        }  else if(strcmp(op,"INSERT") == 0) {
            spt.INSERT();
        }  else if(strcmp(op,"DELETE") == 0) {
            spt.DELETE();
        }  else if(strcmp(op,"MAKE-SAME") == 0) {
            spt.MAKE_SAME();
        }  else if(strcmp(op,"OUT") == 0) {
            spt.OUT();
        }  else if(strcmp(op,"DEBUG") == 0){
            spt.debug();
        }  else if(strcmp(op,"NEWTREE")==0){
            spt.debug();
        }  else {
            spt.REVERSE();
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值