• [BJOI2014]大融合


    Portal

    可以简单发现, 经过一条边的路径条数就是这条边左边的点数乘以右边的点数。

    那么就只要动态维护一棵树两边的点的size就可以了。

    那么就用(整体的点数-子树的点数)就是另外一部分的点数。

    在LCT上,儿子有左儿子,右儿子和虚儿子之分。

    那么我们在维护的时候就分类讨论一下就可以了。

    注意到只有Linkaccess操作会改变虚儿子。 那么我们只要在这个时候维护虚儿子就可以了。


    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
    #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
    #define clar(a, b) memset((a), (b), sizeof(a))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    typedef long long LL;
    typedef long double LD;
    int read() {
        char ch = getchar();
        int x = 0, flag = 1;
        for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
        for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
        return x * flag;
    }
    void write(int x) {
        if (x < 0) putchar('-'), x = -x;
        if (x >= 10) write(x / 10);
        putchar(x % 10 + 48);
    }
    
    template <int N> struct LCT {
        struct node {
            int fa, ch[2], revTag, sumSize, voidSonSize;
        }t[N + 1];
        int _top, stk[N + 1];
    
    #define fa(x) (t[(x)].fa)
    #define lc(x) (t[(x)].ch[0])
    #define rc(x) (t[(x)].ch[1])
    
        bool isroot(int u) { 
            return lc(fa(u)) != u && rc(fa(u)) != u; 
        }
        void pushup(int u) { 
            t[u].sumSize = t[lc(u)].sumSize + t[rc(u)].sumSize + 1 + t[u].voidSonSize; 
        }
        void setRev(int u) {
            t[u].revTag ^= 1, swap(lc(u), rc(u));
        }
        void pushdown(int u) {
            if (t[u].revTag) {
                setRev(lc(u)); setRev(rc(u));
                t[u].revTag = 0;
            }
        }
    
        void rotate(int u) {
            int y = fa(u), z = fa(y), dir = rc(y) == u;
            if (!isroot(y)) t[z].ch[t[z].ch[1] == y] = u; t[u].fa = z;
            t[y].ch[dir] = t[u].ch[dir ^ 1]; t[t[u].ch[dir ^ 1]].fa = y;
            t[u].ch[dir ^ 1] = y; t[y].fa = u;
            pushup(y); pushup(u);
        }
        void splay(int u) {
            stk[_top = 1] = u;
            for (int y = u; !isroot(y); y = fa(y)) stk[++_top] = fa(y); 
            while (_top) pushdown(stk[_top--]);
    
            while (!isroot(u)) {
                int y = fa(u), z = fa(y);
                if (!isroot(y)) 
                    (rc(z) == y) ^ (rc(y) == u) ? rotate(u) : rotate(y);
                rotate(u);
            }
            pushup(u);
        }
    
        void access(int u) {
            for (int y = 0; u; u = fa(y = u)) {
                splay(u);
                t[u].voidSonSize += t[rc(u)].sumSize - t[y].sumSize;
                t[u].ch[1] = y, pushup(u);
            }
        }
        void makeRoot(int u) {
            access(u), splay(u), setRev(u);
        }
        int findRoot(int u) {
            access(u); splay(u);
            while (lc(u)) pushdown(u), u = lc(u);
            return u;
        }
        void link(int u, int v) {
            makeRoot(u); makeRoot(v);
            if (findRoot(u) != v) t[v].fa = u, t[u].voidSonSize += t[v].sumSize, pushup(u);
        }
        void cut(int u, int v) {
            makeRoot(u); access(v); splay(v);
            if (findRoot(v) == u && t[v].ch[0] == u && fa(u) == v) {
                t[v].ch[0] = t[u].fa = 0;
                pushup(v);
            }
        }
    #undef fa
    #undef lc
    #undef rc
    };
    
    const int Maxn = 100009;
    LCT <Maxn> s;
    int n, q;
    
    void init() {
        n = read(); q = read();
    }
    
    void solve() {
        rep (i, 1, n) s.t[i].sumSize = 1;
        rep (i, 1, q) {
            char Cl2 = getchar();
            int H2SO4 = read(), NaCl = read();
            if (Cl2 == 'A') s.link(H2SO4, NaCl);
            if (Cl2 == 'Q') {
                s.makeRoot(H2SO4), s.makeRoot(NaCl);
                LL HCl = 1ll * s.t[H2SO4].sumSize * (1ll * s.t[NaCl].sumSize - s.t[H2SO4].sumSize);
                printf("%lld
    ", HCl);
            }
        }
    }
    
    int main() {
    //	freopen("LG4219.in", "r", stdin);
    //	freopen("LG4219.out", "w", stdout);
    
        init();
        solve();
    
    #ifdef Qrsikno
        debug("
    Running time: %.3lf(s)
    ", clock() * 1.0 / CLOCKS_PER_SEC);
    #endif
        return 0;
    }
    
  • 相关阅读:
    jprofiler配置
    Nginx编译安装
    WebBench的安装与使用
    你经常看到却经常忽视的__init__.py有什么用?
    彻底搞懂Python 中的 import 与 from import
    实现有过期时间的LRU缓存
    实现函数调用结果的 LRU 缓存
    elasticsearch Routing 路由详解
    Elasticsearch _reindex 接口来重新索引数据到新索引,使用新的配置
    浏览器操作elasticsearch别名
  • 原文地址:https://www.cnblogs.com/qrsikno/p/10121074.html
Copyright © 2020-2023  润新知