• BZOJ1500: [NOI2005]维修数列 [splay序列操作]【学习笔记】


    以前写过这道题了,但我把以前的内容删掉了,因为现在感觉没法看

    重写!


    题意:

    维护一个数列,支持插入一段数,删除一段数,修改一段数,翻转一段数,查询区间和,区间最大子序列


    splay序列操作裸题

    需要回收节点编号,所以用到$sz和nw()$,通常维护序列是不用sz的

    splay维护的是这个序列,不再存在平衡树左小右大的性质

    操作一段区间$[l,r]$,将$l-1 splay$到根,$r+1 splay$到右孩子,他的左孩子就是要操作的区间

    为了方便加入两个哨兵节点

    注意splay和线段树不同,每个节点都代表了一个元素

    对于本题来说,因为有可能是修改成0或负数,所以tag=1表示执行了修改操作而不是修改成什么

    下传标记修改会覆盖查询,无论时间先后

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define lc t[x].ch[0]
    #define rc t[x].ch[1]
    #define pa t[x].fa
    typedef long long ll;
    const int N=5e5, INF=1e9;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    
    int n, Q, a[N], k, tot;
    char s[20];
    
    struct meow{
        int ch[2], fa, size, v, sum, mx, lm, rm, tag, rev;
        meow() {}
        meow(int val) {ch[0]=ch[1]=fa=tag=rev=0; size=1; v=sum=mx=lm=rm=val;}
    }t[N];
    int root, sz;
    inline int wh(int x) {return t[pa].ch[1] == x;}
    int st[N], top;
    inline int nw() {return top ? st[top--] : ++sz;}
    
    inline void paint(int x,int v) {
        t[x].tag = 1; t[x].v = v;
        t[x].sum = t[x].size*v;
        t[x].mx = t[x].lm = t[x].rm = max(t[x].sum, v);
        t[x].rev = 0;
    }
    inline void rever(int x) {
        if(t[x].tag) return; //hi
        t[x].rev^=1; 
        swap(lc, rc); swap(t[x].lm, t[x].rm);
    }
    inline void pushDown(int x) {
        if(t[x].rev) {
            if(lc) rever(lc); 
            if(rc) rever(rc);
            t[x].rev=0;
        }
        if(t[x].tag) {
            if(lc) paint(lc, t[x].v); 
            if(rc) paint(rc, t[x].v);
            t[x].tag=0;
        }
    }
    
    inline void update(int x) {
        t[x].size = t[lc].size + t[rc].size + 1;
        t[x].sum = t[lc].sum + t[rc].sum + t[x].v;
        t[x].mx = max(max(t[lc].mx, t[rc].mx), max(0, t[lc].rm) + t[x].v + max(0, t[rc].lm) );
        t[x].lm = max(t[lc].lm, t[lc].sum + t[x].v + max(0, t[rc].lm) );
        t[x].rm = max(t[rc].rm, t[rc].sum + t[x].v + max(0, t[lc].rm) );
    }
    
    inline void rotate(int x) {
        int f=t[x].fa, g=t[f].fa, c=wh(x);
        if(g) t[g].ch[wh(f)]=x; t[x].fa=g;
        t[f].ch[c] = t[x].ch[c^1]; t[t[f].ch[c]].fa=f;
        t[x].ch[c^1]=f; t[f].fa=x;
        update(f); update(x);
    }
    inline void splay(int x,int tar) {
        for(; pa!=tar; rotate(x))
            if(t[pa].fa != tar) rotate(wh(x)==wh(pa) ? pa : x);
        if(tar==0) root=x;
    }
    
    void build(int &x,int l,int r,int f) {
        int mid = (l+r)>>1;
        x=nw(); t[x]=meow(a[mid]); t[x].fa=f;
        if(l==r) return;
        if(l<mid) build(lc, l, mid-1, x);
        if(mid<r) build(rc, mid+1, r, x);
        update(x);
    }
    
    inline int kth(int k) {
        int x=root, lsize=0;
        while(x) {
            pushDown(x);
            int _ = lsize + t[lc].size;
            if(k<=_) x=lc;
            else if(k<=_+1) return x;
            else lsize=_+1, x=rc;
        }
        return -1;
    }
    
    void Ins(int k, int tot) {
        for(int i=1; i<=tot; i++) a[i]=read();
        int f=kth(k+1); splay(f, 0);
        int x=kth(k+2); splay(x, f);
        build(lc, 1, tot, x);
        update(x); update(f);
    }
    
    void erase(int x) {
        if(!x) return;
        st[++top]=x;
        erase(lc); erase(rc);
    }
    void Del(int k, int tot) {
        int f=kth(k); splay(f, 0);
        int x=kth(k+tot+1); splay(x, f);
        erase(lc); lc=0;
        update(x); update(f);
    }
    
    void Mak(int k, int tot) {
        int f=kth(k); splay(f, 0);
        int x=kth(k+tot+1); splay(x, f);
        paint(lc, read());
        update(x); update(f);
    }
    
    void Rev(int k, int tot) {
        int f=kth(k); splay(f, 0);
        int x=kth(k+tot+1); splay(x, f);
        rever(lc);
        update(x); update(f);
    }
    
    int Sum(int k, int tot) {
        int f=kth(k); splay(f, 0);
        int x=kth(k+tot+1); splay(x, f);
        return t[lc].sum;
    }
    
    int main() {
        //freopen("in","r",stdin);
        n=read(); Q=read();
        for(int i=2; i<=n+1; i++) a[i]=read(); a[1] = a[n+2] = -INF;
        t[0]=meow(-INF); t[0].sum=t[0].size=0; 
        build(root, 1, n+2, 0);
        for(int i=1; i<=Q; i++) { //printf("Q %d
    ",i);
            scanf("%s",s+1); 
            if(s[3]=='X') printf("%d
    ", t[root].mx);
            else {
                k=read(); tot=read();
                if(s[1]=='I') Ins(k, tot);
                if(s[1]=='D') Del(k, tot);
                if(s[1]=='M') Mak(k, tot);
                if(s[1]=='R') Rev(k, tot);
                if(s[1]=='G') printf("%d
    ", Sum(k, tot));
            }
        }
    }
  • 相关阅读:
    setContentView和inflate区别
    Android之用HTTP的get,post,HttpClient三种方式向service提交文本数据
    用C#製作PDF文件全攻略
    移动平台前端开发总结(针对iphone,Android等手机)
    Android实现左右滑动指引效果
    为 iPhone 和 iPad 自定义网站的主屏幕图标
    android 布局中的单位及分辨率自解
    纯css页面变灰度兼容ie、firefox、chrome、opera、safari
    Android判断网络连接是否可用(代码)
    Android实现渐显按钮的左右滑动效果
  • 原文地址:https://www.cnblogs.com/candy99/p/6129899.html
Copyright © 2020-2023  润新知