[一类维护形态树和值树的LCT]BZOJ 3159: 决战

Solution

首先这道题可以用 Treap 加树链剖分。
LCT 的话,要维护两片 Splay 森林。
一片为形态树森林,就相当于最原来的 LCT
一片为值树森林,维护相应节点的权值。
通过对两片森林的同时操作,可以保证每时每刻两片森林可以通过旋转形态相同。
在形态树森林的根节点维护一个值树的指针,指向相应位置的值树森林的根节点。其余节点的指针指向空。
每次要找到形态树节点在值树对应的节点,就相当于在值树找到相应中序遍历的节点。
另外旋转的时候要把根节点的值树指针准确的转移。
LCT 还有一个操作就是 Access 。就是把一些实边变成虚边,一些虚边变成实边。
那么在值树上就是合并两棵 Splay
因为题目保证了深度是单调的,所以直接接上边就好了。
实现了好久哦。。。。

#include <bits/stdc++.h>
using namespace std;

const int N = 101010;
const int INF = 1 << 30;
typedef long long ll;

struct ValTree {
    struct node {
        node *ch[2];
        node *fa;
        int rev, mn, mx, key, add, size;
        ll sum;
        inline void PushDown(node *null) {
            if (rev) {
                if (ch[0] != null) ch[0]->reverse();
                if (ch[1] != null) ch[1]->reverse();
                rev = 0;
            }
            if (add) {
                if (ch[0] != null) ch[0]->Add(add);
                if (ch[1] != null) ch[1]->Add(add);
                add = 0;
            }
        }
        inline void Add(int ad) {
            add += ad; key += ad;
            mx += ad; mn += ad;
            sum += (ll)ad * size;
        }
        inline void PushUp(void) {
            mn = min(ch[0]->mn, ch[1]->mn);
            mn = min(mn, key);
            mx = max(ch[0]->mx, ch[1]->mx);
            mx = max(mx, key);
            sum = key + ch[0]->sum + ch[1]->sum;
            size = ch[0]->size + ch[1]->size + 1;
        }
        inline void reverse(void) {
            rev ^= 1; swap(ch[0], ch[1]);
        }
    };
    node *null;
    node T[N];
    inline void Down(node *x) {
        if (x->fa != null) Down(x->fa);
        x->PushDown(null);
    }
    inline void Rotate(node *x) {
        node *y = x->fa, *z = y->fa;
        int l = (y->ch[0] != x), r = l ^ 1;
        if (y->fa != null) {
            if (z->ch[0] == y) z->ch[0] = x;
            else z->ch[1] = x;
        }
        x->fa = z; y->fa = x; x->ch[r]->fa = y;
        y->ch[l] = x->ch[r]; x->ch[r] = y;
        y->PushUp(); x->PushUp();
    }
    inline void Splay(node *x) {
        Down(x);
        while (x->fa != null) {
            node *y = x->fa, *z = y->fa;
            if (y->fa != null) {
                if (y->ch[0] == x ^ z->ch[0] == y) Rotate(x);
                else Rotate(y);
            }
            Rotate(x);
        }
    }
    inline node *Kth(node *x, int k) {
        x->PushDown(null);
        if (x->size < k) return null;
        node *o = x;
        while (k) {
            o->PushDown(null);
            if (o->ch[0]->size + 1 < k) {
                k -= o->ch[0]->size + 1;
                o = o->ch[1];
            } else if (o->ch[0]->size >= k) {
                o = o->ch[0];
            } else break;
        }
        Splay(o); return o;
    }
    inline void NewNode(node *x) {
        x->ch[0] = x->ch[1] = x->fa = null;
        x->sum = x->key = x->size = 0;
        x->mn = x->mx = 0;
        x->rev = x->add = 0;
    }
    void Init(int n) {
        NewNode(null = T);
        null->mn = INF; null->mx = -1;
        for (int i = 1; i <= n; i++) {
            NewNode(T + i);
            T[i].size = 1;
        }
    }
    inline void Travel(node *x) {
        if (x == null) return;
        Travel(x->ch[0]);
        printf("%d\n", x->key);
        Travel(x->ch[1]);
    }
};
ValTree VT;
typedef ValTree::node Vnode;
struct LCT {
    struct node {
        node *ch[2];
        node *fa;
        int rev, size;
        Vnode *val;
        inline void PushDown(void) {
            if (rev) {
                ch[0]->reverse();
                ch[1]->reverse();
                rev = 0;
            }
        }
        inline void PushUp(void) {
            size = ch[0]->size + ch[1]->size + 1;
        }
        inline void reverse(void) {
            rev ^= 1; swap(ch[0], ch[1]);
        }
    };
    node *null;
    node T[N];
    inline bool IsRoot(node *x) {
        return x->fa == null || (x->fa->ch[0] != x && x->fa->ch[1] != x);
    }
    inline void Down(node *x) {
        if (!IsRoot(x)) Down(x->fa);
        x->PushDown();
    }
    inline void Rotate(node *x) {
        node *y = x->fa, *z = y->fa;
        int l = (y->ch[0] != x), r = l ^ 1;
        if (!IsRoot(y)) {
            if (z->ch[0] == y) z->ch[0] = x;
            else z->ch[1] = x;
        }
        x->fa = z; y->fa = x; x->ch[r]->fa = y;
        y->ch[l] = x->ch[r]; x->ch[r] = y;
        y->PushUp(); x->PushUp();
        swap(y->val, x->val);
    }
    inline void Splay(node *x) {
        Down(x);
        while (!IsRoot(x)) {
            node *y = x->fa, *z = y->fa;
            if (!IsRoot(y)) {
                if (y->ch[0] == x ^ z->ch[0] == y) Rotate(x);
                else Rotate(y);
            }
            Rotate(x);
        }
    }
    inline void Access(node *x) {
        for (node *t = null; x != null; x = x->fa) {
            Splay(x);
            if (x->ch[1] != null) {
                int k = x->ch[0]->size + 2;
                Vnode *y = VT.Kth(x->val, k);
                Vnode *z = y->ch[0];
                x->ch[1]->val = y;
                y->ch[0]->fa = VT.null; y->ch[0] = VT.null; y->PushUp();
                x->val = z; VT.Splay(x->val);
            }
            if (t != null) {
                int k = x->val->size;
                Vnode *y = VT.Kth(x->val, k);
                y->ch[1] = t->val; t->val->fa = y; y->PushUp();
                t->val = VT.null; VT.Splay(x->val);
            }
            x->ch[1] = t; x->PushUp(); t = x;
        }
    }
    inline void MakeRoot(node *x) {
        Access(x); Splay(x);
        x->reverse(); x->val->reverse();
    }
    inline int Min(node *x, node *y) {
        MakeRoot(x); Access(y); Splay(y);
        return y->val->mn;
    }
    inline int Max(node *x, node *y) {
        MakeRoot(x); Access(y); Splay(y);
        return y->val->mx;
    }
    inline ll Sum(node *x, node *y) {
        MakeRoot(x); Access(y); Splay(y);
        return y->val->sum;
    }
    inline int Add(node *x, node *y, int k) {
        MakeRoot(x); Access(y); Splay(y);
        y->val->Add(k);
    }
    inline int Rev(node *x, node *y) {
        MakeRoot(x); Access(y); Splay(y);
        y->val->reverse();
    }
    void Init(int n) {
        VT.Init(n); null = T;
        null->fa = null->ch[0] = null->ch[1] = null;
        null->size = 0;
        for (int i = 1; i <= n; i++) {
            T[i].val = VT.T + i;
            T[i].fa = T[i].ch[0] = T[i].ch[1] = null;
            T[i].size = 1; T[i].rev = 0;
        }
    }
    inline void AddEdge(int x, int y) {
        MakeRoot(T + x); T[x].fa = T + y;
    }
};
LCT ST;

char opt[123];
int n, m, x, y, z;

int main(void) {
    scanf("%d%d%d", &n, &m, &x);
    ST.Init(n);
    for (int i = 1; i < n; i++) {
        scanf("%d%d\n", &x, &y);
        ST.AddEdge(x, y);
    }
    for (int i = 1; i <= m; i++) {
        scanf("%s %d%d", opt, &x, &y);
        if (opt[2] == 'c') {
            scanf("%d", &z);
            ST.Add(ST.T + x, ST.T + y, z);
        } else if (opt[0] == 'S') {
            printf("%lld\n", ST.Sum(ST.T + x, ST.T + y));
        } else if (opt[1] == 'a') {
            printf("%d\n", ST.Max(ST.T + x, ST.T + y));
        } else if (opt[0] == 'M') {
            printf("%d\n", ST.Min(ST.T + x, ST.T + y));
        } else {
            ST.Rev(ST.T + x, ST.T + y);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值