P2042 [NOI2005]维护数列

毒瘤模板题!!!!

这道题看到什么维护序列的,肯定就是用数据结构的。

这个东西叫你做下面的事情:

首先确定用什么数据结构。

看到翻转,二话不说就用splay。

第一个操作:在第posi位后加入tot个数字。我们就把这一段数字建出一个子splay。用类似线段树的建树方式解决掉,比一个一个加入的建树方式快,常数小。然后split出来中间的位置,暴力连接,pushup即可。

第二个操作:在第posi位后连续删除tot个数字。我们spilt出来这段数字,然后暴力断开与主splay的链接。主splaypushup一下,子splay就直接删除掉即可。

第三个操作:推平一段区间。我们使用lazy标记记录一下即可。我们先表面改好,然后再给子节点加lazy标记。听起来不难。

第四个操作:区间翻转。我们同样使用懒标记的思想。具体操作看“文艺平衡树”那道模板题。

第五个操作:求区间和。维护一下就是了。。。

第六个操作:求最大子序列。

这个问题最初是在线段树上的。

\(O(n)\)的算法能求一个固定数的最大子序列,但是一次修改就得跟一个\(O(n)\)是很慢的。

其实最大子序列有一个分治解法,是\(O(nlogn)\)的。这种方法可以用到线段树里面,使得一个修改是\(O(logn)\)的。

具体就是一个节点跟三个变量:mxlxrx

如何更新?放在pushup里面更新。更新方法像在dp一样:

\(lx[l,r]=max(lx[l,mid],sum[l,mid]+lx[mid+1,r])\)

\(rx[l,r]=max(rx[mid+1,r],sum[mid+1,r]+rx[l,mid])rx[l,r]=max(rx[mid+1,r],sum[mid+1,r]+rx[l,mid])\)

\(mx[l,r]=max(mx[l,mid],mx[mid+1,r],lx[mid+1,r]+rx[l,mid+1])mx[l,r]=max(mx[l,mid],mx[mid+1,r],lx[mid+1,r]+rx[l,mid+1])\)

放在平衡树也简单,不就是多出了一个单独的节点\(mid\)吗?算进去就是了。

接下来麻烦的就来了!如何搞定这些懒标记的复杂关系?

显然,一个有推平标记的翻转没意义。所以可以直接忽略掉。所以先处理推平,后处理翻转。

翻转不只要交换左右儿子!还需要交换lxrx

翻转的写法我之前是直接改标记后就走人,所以他上面的根本就没改到。如果单纯只叫你维护翻转的话那样写是没问题的。

注意

  • mx[0]a[1]a[n+2]都要设为-INF。因为有最大子序列。

  • 注意pushup!!!

  • 细心加耐心!!!

代码:

#include<cstdio>
#include<algorithm>
#include<stack>

const int maxn = 500005;
const int INF = 0x3f3f3f3f;

int a[maxn], id[maxn];
int fa[maxn], size[maxn], ch[maxn][2];
int val[maxn], sum[maxn];
int lx[maxn], mx[maxn], rx[maxn];
bool lazy[maxn], rev[maxn];
int root, tot;
int n, m;
std::stack<int> sta;

#define lson ch[x][0]
#define rson ch[x][1]
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar();
    return s * ans;
}
int newnode()
{
    if(!sta.empty())
    {
        int ret = sta.top(); sta.pop();
        return ret;
    }
    return ++tot;
}
void clear_it(int x)
{
    fa[x] = size[x] = ch[x][0] = ch[x][1] = val[x] = sum[x] = lx[x] = mx[x] = rx[x] = lazy[x] = rev[x] = 0;
}
int dir(int x)
{
    return ch[fa[x]][1] == x;
}
void connect(int son, int f, int k)
{
    fa[son] = f; ch[f][k] = son;
}
void pushup(int x)
{
    size[x] = size[lson] + size[rson] + 1;
    sum[x] = sum[lson] + sum[rson] + val[x];
    lx[x] = std::max(lx[lson], sum[lson] + val[x] + lx[rson]);
    rx[x] = std::max(rx[rson], sum[rson] + val[x] + rx[lson]);
    mx[x] = std::max(std::max(mx[lson], mx[rson]), rx[lson] + val[x] + lx[rson]);
}
void rotate(int x)
{
    int y = fa[x];
    int z = fa[y];
    int yk = dir(x);
    int zk = dir(y);
    int b = ch[x][yk ^ 1];
    connect(b, y, yk);
    connect(y, x, yk ^ 1);
    connect(x, z, zk);
    pushup(y);
    pushup(x);
}
void splay(int x, int goal)
{
    while(fa[x] != goal)
    {
        int y = fa[x];
        int z = fa[y];
        if(z != goal) dir(x) == dir(y) ? rotate(y) : rotate(x);
        rotate(x);
    }
    if(goal == 0) root = x;
}
void pushdown(int x)
{
    if(lazy[x])
    {
        lazy[x] = rev[x] = 0;
        if(lson)
        {
            val[lson] = val[x]; sum[lson] = val[x] * size[lson];
            if(val[x] >= 0) mx[lson] = lx[lson] = rx[lson] = sum[lson];
            else mx[lson] = val[lson], lx[lson] = rx[lson] = 0;
            lazy[lson] = 1;
        }
        if(rson)
        {
            val[rson] = val[x]; sum[rson] = val[x] * size[rson];
            if(val[x] >= 0) mx[rson] = lx[rson] = rx[rson] = sum[rson];
            else mx[rson] = val[rson], lx[rson] = rx[rson] = 0;
            lazy[rson] = 1;
        }
    }
    if(rev[x])
    {
        rev[x] = 0;
        std::swap(ch[lson][0], ch[lson][1]);
        std::swap(lx[lson], rx[lson]);
        std::swap(ch[rson][0], ch[rson][1]);
        std::swap(lx[rson], rx[rson]);
        rev[lson] ^= 1; rev[rson] ^= 1;
    }
}
int build(int f, int l, int r)
{
    if(l > r) return 0;
    if(l == r)
    {
        val[id[l]] = sum[id[l]] = a[l];
        fa[id[l]] = id[f];
        size[id[l]] = 1;
        ch[id[l]][0] = ch[id[l]][1] = lazy[id[l]] = rev[id[l]] = 0;
        mx[id[l]] = a[l];
        lx[id[l]] = rx[id[l]] = std::max(a[l], 0);
        return id[l];
    }
    int mid = (l + r) >> 1;
    val[id[mid]] = a[mid];
    fa[id[mid]] = id[f];
    ch[id[mid]][0] = build(mid, l, mid - 1);
    ch[id[mid]][1] = build(mid, mid + 1, r);
    pushup(id[mid]);
    return id[mid];
}
int kth(int k)
{
    int x = root;
    while(2333)
    {
        pushdown(x);
        if(size[lson] + 1 < k)
        {
            k -= size[lson] + 1;
            x = rson;
        }
        else if(size[lson] >= k) x = lson;
        else return x;
    }
}
int split(int l, int r)
{
    l = kth(l), r = kth(r);
    splay(l, 0), splay(r, l);
    return ch[r][0];
}
void recycle(int x)
{
    if(lson) recycle(lson);
    if(rson) recycle(rson);
    clear_it(x);
    sta.push(x);
}
// functions
void Insert()
{
    int posi = read(), tot = read();
    for(int i = 1; i <= tot; i++) a[i] = read(), id[i] = newnode();
    int del = build(0, 1, tot);
    split(posi + 1, posi + 2);
    connect(del, ch[root][1], 0);
    pushup(ch[root][1]);// 10pt
    pushup(root);
}
void Delete()
{
    int posi = read(), tot = read();
    int del = split(posi, posi + tot + 1);
    ch[ch[root][1]][0] = 0; fa[del] = 0;// disconnect
    pushup(ch[root][1]);
    pushup(root);
    recycle(del);
}
void Reverse()
{
    int posi = read(), tot = read();
    int del = split(posi, posi + tot + 1);
    
    rev[del] ^= 1;
    std::swap(ch[del][0], ch[del][1]);
    std::swap(lx[del], rx[del]);
    pushup(ch[root][1]);// 90pt
    pushup(root);
}
void GetSum()
{
    int posi = read(), tot = read();
    int del = split(posi, posi + tot + 1);
    printf("%d\n", sum[del]);
}
void MakeSame()
{
    int posi = read(), tot = read(), c = read();
    int del = split(posi, posi + tot + 1);
    val[del] = c; sum[del] = c * size[del];
    if(val[del] >= 0) lx[del] = rx[del] = mx[del] = sum[del];
    else mx[del] = val[del], lx[del] = rx[del] = 0;
    lazy[del] = 1;
    pushup(ch[root][1]);
    pushup(root);
}
void MaxSum()
{
    printf("%d\n", mx[root]);
}
// debug
void print(int x)
{
    if(lson) print(lson);
    printf("%d ", val[x]);
    if(rson) print(rson);
}
int main()
{
    //freopen("testdata.in", "r", stdin);
    //freopen("Test.out", "w", stdout);
    n = read(), m = read();
    mx[0] = a[1] = a[n+2] = -INF;
    for(int i = 2; i <= n + 1; i++) a[i] = read();
    for(int i = 1; i <= n + 2; i++) id[i] = ++tot;// give them id
    root = build(0, 1, n + 2);
    //print(root); printf("\n");
    char opt[15];
    while(m--)
    {
        scanf("%s", opt);
        if(opt[0] == 'I') Insert();
        else if(opt[0] == 'D') Delete();
        else if(opt[0] == 'R') Reverse();
        else if(opt[0] == 'G') GetSum();
        else if(opt[2] == 'K') MakeSame();
        else if(opt[2] == 'X') MaxSum();
        //print(root); printf("\n");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Garen-Wang/p/9697403.html
今日推荐