zoukankan      html  css  js  c++  java
  • NOI2005 维护数列

    传送门

    我还是没有逃过在这道题上debug好久的命运……

    我是使用(fhq-treap)来做的这道题。写的时候写的挺爽的……调的时候真难受。

    首先我们先来说说咋做吧。前5个操作对于(fhq-treap)来说不在话下,只要多打两个标记就可以了。但是如何求最大子段和?

    我们一般只会想到一种(O(n))的做法吧。但是这样必然超时。其实这个还有另一种分治的做法,我们在线段树上可能会经常用到,就是维护每个节点从左,右,和在它内部的连续最大字段和。之后我们通过左右儿子来进行合并即可。有一道题传送门(SDOI2011 染色) 就用到了这种做法,不过维护的不是最大字段和(滑稽)

    于是乎我们再打三个标记来维护它……(雾

    然后我们就开始非常开心的敲。敲完之后发现,de不出来啊……

    这里有以下和正确性相关的细节。

    1.merge的时候,要先进行pushdown。我们一般的写法,是只要遇到有一个空树就进行返回。但是这道题中因为要维护最大子段和,需要用左右的来归并,而如果其中有一棵是空树,就会导致另一个没有pushdown,从而影响答案的正确性。

    2.在区间翻转的时候要注意。我们需要先翻转自己的左右儿子,之后在标记下放的时候,对左右儿子旋转左右儿子。

    3.注意一点就是,对于一个区间的从左/右开始的连续最大子段和,我们必须在它的左/右儿子存在的时候才可以进行更新。一个重要原因是这题有负数,就会导致你把负的答案改成0,使得出错。

    4.这个题因为插入和删除很多,所以要进行垃圾回收。回收之后再拿出来的时候,我们需要进行重置,清空所有原来的数据,否则一旦与原来有关联就不知道会发生啥了。

    之后还是有好多细节的……基本上都是对于最大子段和的更新过程,确实是比较繁琐的,需要时刻判断一下是否有左右儿子存在来进行计算。

    看一下代码。

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define I inline
    
    using namespace std;
    typedef long long ll;
    const int M = 1000005;
    
    I int read()
    {
        int ans = 0,op = 1;char ch = getchar();
        while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
        while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
        return ans * op; 
    }
    
    struct tree
    {
        int lc,rc,size,sum,val,mx,lx,rx,opv,rk;
        bool opt,rev;
    }t[M<<1];
    
    int bin[M<<3],bintop,n,m,tot,sta[M<<1],top;
    char s[20];
    
    I int newnode(int x)
    {
        int g = bintop ? bin[bintop--] : ++tot;
        t[g].size = 1,t[g].sum = t[g].val = t[g].mx = x;
        t[g].opv = t[g].lc = t[g].rc = 0;
        t[g].opt = t[g].rev = 0;
        t[g].rx = t[g].lx = max(0,x),t[g].rk = rand();
        return g;
    }
    
    I void pushup(int x)
    {
        t[x].size = t[t[x].lc].size + t[t[x].rc].size + 1;
        t[x].sum = t[t[x].lc].sum + t[t[x].rc].sum + t[x].val;
        t[x].mx = max(t[x].val,t[t[x].lc].rx + t[t[x].rc].lx + t[x].val);
        if(t[x].lc) t[x].mx = max(t[x].mx,t[t[x].lc].mx);
        if(t[x].rc) t[x].mx = max(t[x].mx,t[t[x].rc].mx);
        t[x].lx = max(t[t[x].lc].lx,t[t[x].lc].sum + t[x].val + t[t[x].rc].lx);
        t[x].rx = max(t[t[x].rc].rx,t[t[x].rc].sum + t[x].val + t[t[x].lc].rx);
    }
    
    I void rever(int x) {swap(t[x].lx,t[x].rx),swap(t[x].lc,t[x].rc),t[x].rev ^= 1;}
    I void cover(int x,int v)
    {
        t[x].val = v,t[x].sum = t[x].size * v;
        t[x].lx = t[x].rx = max(t[x].sum,0);
        t[x].mx = max(t[x].sum,t[x].val),t[x].opv = v,t[x].opt = 1;
    }
    
    I void pushdown(int x)
    {
        if(t[x].rev) 
        {
            if(t[x].lc) rever(t[x].lc);
            if(t[x].rc) rever(t[x].rc);
            t[x].rev ^= 1;
        }
        if(t[x].opt)
        {
            if(t[x].lc) cover(t[x].lc,t[x].opv);
            if(t[x].rc) cover(t[x].rc,t[x].opv);
            t[x].opt = 0,t[x].opv = 0;
        }
    }
    
    int build(int l,int r,int *a)
    {
        if(l > r) return 0;
        int mid = (l+r) >> 1;
        int g = newnode(a[mid]);
        t[g].lc = build(l,mid-1,a),t[g].rc = build(mid+1,r,a);
        pushup(g);
        return g;
    }
    
    int merge(int x,int y)
    {
        pushdown(x),pushdown(y);
        if(!x || !y) return x | y;
        if(t[x].rk < t[y].rk) {t[x].rc = merge(t[x].rc,y),pushup(x);return x;}
        else {t[y].lc = merge(x,t[y].lc),pushup(y);return y;}
    }
    
    void splits(int u,int k,int &x,int &y)
    {
        if(!u) x = y = 0;
        else
        {
            pushdown(u);
            if(t[t[u].lc].size >= k) y = u,splits(t[u].lc,k,x,t[u].lc);
            else x = u,splits(t[u].rc,k - t[t[u].lc].size - 1,t[u].rc,y);
            pushup(u);
        }
    }
    
    void restore(int x)
    {
        if(!x) return;
        bin[++bintop] = x,restore(t[x].lc),restore(t[x].rc);
    }
    
    int a[M<<2],root,pos,num,x,y,z;
    
    int main()
    {
        srand(time(NULL));
        n = read(),m = read();
        rep(i,1,n) a[i] = read();
        root = build(1,n,a);
        while(m--)
        {
            scanf("%s",s);
            if(s[0] == 'G') 
            {
                pos = read(),num = read();
                if(num == 0) {printf("0
    ");continue;}
                splits(root,pos-1,x,y),splits(y,num,z,y);
                printf("%d
    ",t[z].sum);
                root = merge(x,merge(z,y));
            }
            if(s[0] == 'I') 
            {
                pos = read(),num = read();
                if(num == 0) continue;
                rep(i,1,num) a[i] = read();
                int nroot = build(1,num,a);
                splits(root,pos,x,y),root = merge(merge(x,nroot),y);
            }
            if(s[0] == 'D')
            {
                pos = read(),num = read();
                if(num == 0) continue;
                splits(root,pos-1,x,y),splits(y,num,z,y);
                root = merge(x,y),restore(z);
            }
            if(s[0] == 'M' && s[2] == 'K') 
            {
                pos = read(),num = read();
                int v = read();
                if(num == 0) continue;
                splits(root,pos-1,x,y),splits(y,num,z,y);
                cover(z,v),root = merge(x,merge(z,y));
            }
            if(s[0] == 'M' && s[2] == 'X') printf("%d
    ",t[root].mx);
            if(s[0] == 'R')
            {
                pos = read(),num = read();
                if(num == 0) continue;
                splits(root,pos-1,x,y),splits(y,num,z,y);
                rever(z),root = merge(x,merge(z,y));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Models(Pascal)
    Summer Plan(挖坑待填)
    C++之指针
    QuickPower快速幂
    codevs 1231最优布线问题
    颓废了1年+,今天开始勤(tui)奋(fei)啦
    l'Hopital法则
    相律
    小意外
    一种改进的动力学处理方法
  • 原文地址:https://www.cnblogs.com/captain1/p/10303592.html
Copyright © 2011-2022 走看看