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;
    }
    
  • 相关阅读:
    工作中遇到的java 内存溢出,问题排查
    java线上内存溢出问题排查步骤
    性能测试-java内存溢出问题排查
    164 01 Android 零基础入门 03 Java常用工具类01 Java异常 04 使用try…catch…finally实现异常处理 04 终止finally执行的方法
    163 01 Android 零基础入门 03 Java常用工具类01 Java异常 04 使用try…catch…finally实现异常处理 03 使用多重catch结构处理异常
    162 01 Android 零基础入门 03 Java常用工具类01 Java异常 04 使用try…catch…finally实现异常处理 02 使用try-catch结构处理异常
    161 01 Android 零基础入门 03 Java常用工具类01 Java异常 04 使用try…catch…finally实现异常处理 01 try-catch-finally简介
    160 01 Android 零基础入门 03 Java常用工具类01 Java异常 03 异常处理简介 01 异常处理分类
    159 01 Android 零基础入门 03 Java常用工具类01 Java异常 02 异常概述 02 异常分类
    158 01 Android 零基础入门 03 Java常用工具类01 Java异常 02 异常概述 01 什么是异常?
  • 原文地址:https://www.cnblogs.com/captain1/p/10303592.html
Copyright © 2011-2022 走看看