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('\n')
#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\n");continue;}
            splits(root,pos-1,x,y),splits(y,num,z,y);
            printf("%d\n",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\n",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;
}
posted @ 2019-01-22 14:20  CaptainLi  阅读(229)  评论(0编辑  收藏  举报