• Luogu 3302 [SDOI2013]森林


    BZOJ 3123

    丑陋的常数,BZOJ 19968ms 卡过。

    感觉几个思想都挺经典但是挺套路的。

    先考虑不连边的情况怎么做,区间第$k$小,想到主席树,每一个结点维护它到根的前缀和,这样子每一次查询$x$到$y$链上的点就相当于主席树上$sum(x) + sum(y) - sum(lca(x, y)) - sum(fa(lca(x, y)))$,时间复杂度一个$log$。

    然后想一想连边怎么做,因为我们要维护一个森林的形态,如果暴力连边的话,相当于把$y$作为根建树连到$x$上,我们有一个优化暴力的办法就是每一次都把$siz$小的那一个点建树连到另一个点。

    然后发现这样的复杂度就已经对了,证明方法和树剖类似,相当于每一次合并$siz$都会至少扩大一倍,所以对于一个大小为$n$的集合,至多会合并$logn$次,总复杂度$O(nlogn)$,这东西有一个名字叫做启发式合并。

    时间复杂度$O(nlog^{2}n)$。

    还有一个算是坑点的东西:

    (我也是)

    虽然感觉题目说得很清楚了,但是我还是没有看

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N = 80005;
    const int Lg = 18;
    const int M = 4e7 + 5;
    const int inf = 1 << 30;
    
    int testCase, n, m, qn, tot, head[N];
    int ans, maxn, ufs[N], siz[N];
    int fa[N][Lg], dep[N], a[N], v[N];
    bool vis[N];
    
    struct Edge {
        int to, nxt;
    } e[N << 1];
    
    inline void add(int from, int to) {
        e[++tot].to = to;
        e[tot].nxt = head[from];
        head[from] = tot;
    }
    
    struct Innum {
        int val, id;
    } in[N];
    
    bool cmp(const Innum &x, const Innum &y) {
        if(x.val != y.val) return x.val < y.val;
        else return x.id < y.id;
    }
    
    inline void chkMax(int &x, int y) {
        if(y > x) x = y;
    }
    
    inline void discrete() {
        sort(in + 1, in + 1 + n, cmp);
        in[0].val = -inf;
        
        for(int cnt = 0, i = 1; i <= n; i++) {
            if(in[i].val != in[i - 1].val) chkMax(maxn, ++cnt);
            a[in[i].id] = cnt;
            v[cnt] = in[i].val;
        }
    }
    
    inline void read(int &X) {
        X = 0; char ch = 0; int op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    inline void init() {
        for(int i = 1; i <= n; i++)
            ufs[i] = i, siz[i] = 1;
    }
    
    int find(int x) {
        return ufs[x] == x ? x : ufs[x] = find(ufs[x]);
    }
    
    namespace PSegT {
        struct Node {
            int lc, rc, sum;
        } s[M];
        int root[N], nodeCnt;
        
        #define mid ((l + r) >> 1)
        
        inline void up(int p) {
            if(!p) return;
            s[p].sum = s[s[p].lc].sum + s[s[p].rc].sum;
        }
        
        void ins(int &p, int l, int r, int x, int pre) {
            s[p = ++nodeCnt] = s[pre], s[p].sum++;
            if(l == r) return;
            
            if(x <= mid) ins(s[p].lc, l, mid, x, s[pre].lc);
            else ins(s[p].rc, mid + 1, r, x, s[pre].rc);
            
            up(p);
        }
        
        int query(int x, int y, int z, int w, int l, int r, int k) {
            if(l == r) return l;
            
            int now = s[s[x].lc].sum + s[s[y].lc].sum - s[s[z].lc].sum - s[s[w].lc].sum;
            
            if(k <= now) return query(s[x].lc, s[y].lc, s[z].lc, s[w].lc, l, mid, k);
            else return query(s[x].rc, s[y].rc, s[z].rc, s[w].rc, mid + 1, r, k - now);
        }
        
    } using namespace PSegT;
    
    void dfs1(int x, int fat) {
        vis[x] = 1, dep[x] = dep[fat] + 1, fa[x][0] = fat;
        for(int i = 1; i <= 16; i++)
            fa[x][i] = fa[fa[x][i - 1]][i - 1];
        for(int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            if(y == fat) continue;
            dfs1(y, x);
        }
    }
    
    inline void swap(int &x, int &y) {
        int t = x; x = y; y = t;
    }
    
    inline int getLca(int x, int y) {
        if(dep[x] < dep[y]) swap(x, y);
        for(int i = 16; i >= 0; i--)
            if(dep[fa[x][i]] >= dep[y])
                x = fa[x][i];
        if(x == y) return x;
        for(int i = 16; i >= 0; i--)    
            if(fa[x][i] != fa[y][i])    
                x = fa[x][i], y = fa[y][i];
        return fa[x][0];
    }
    
    void dfs2(int x) {
        root[x] = 0, ins(root[x], 1, maxn, a[x], root[fa[x][0]]);
        for(int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            if(y == fa[x][0]) continue;
            dfs2(y);
        }
    }
    
    inline void solve() {
        int x, y, k;
        read(x), read(y), read(k);
        x ^= ans, y ^= ans, k ^= ans;
        int z = getLca(x, y), w = fa[z][0];
        int res = query(root[x], root[y], root[z], root[w], 1, maxn, k);
        printf("%d
    ", ans = v[res]);
    }
    
    int main() {
        read(testCase);
        for(testCase = 1; testCase--; ) {
            read(n), read(m), read(qn);
            
            memset(head, 0, sizeof(head)); tot = maxn = 0;
            init();
            
            for(int i = 1; i <= n; i++) {
                read(a[i]);
                in[i] = (Innum) {a[i], i};
            }
            discrete();
            
            for(int x, y, i = 1; i <= m; i++) {
                read(x), read(y);
                add(x, y), add(y, x);
                
                int fx = find(x), fy = find(y);
                if(fx != fy) {
                    ufs[fx] = fy;
                    siz[fy] += siz[fx];
                }
            }
            
            memset(vis, 0, sizeof(vis));
            memset(root, 0, sizeof(root)); nodeCnt = 0;
            for(int i = 1; i <= n; i++) {
                if(vis[i]) continue;
                dfs1(find(i), 0), dfs2(find(i));
            }
            
            ans = 0;
            for(char op[3]; qn--; ) {
                scanf("%s", op);
                if(op[0] == 'Q') solve();
                else {
                    int x, y; 
                    read(x), read(y);
                    x ^= ans, y ^= ans;
                    
                    int fx = find(x), fy = find(y);
                    if(siz[fx] > siz[fy]) swap(fx, fy);
                    
                    add(x, y), add(y, x);
                    dfs1(y, x), dfs2(y);
                    
                    ufs[fy] = fx, siz[fx] += siz[fy];
                }
            }
            
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Xshell的一些使用方法和注意事项
    adobe premiere pro cc2015.0已停止工作 解决办法
    视频播放效果--video.js播放mp4文件
    centos 7.0 编译安装php 7.0.3
    centos 7.0 安装nginx 1.9.10
    centos 7.0 firewall 防火墙常用命令
    webstorm 更改默认服务器端口
    css3 动画效果 定义和绑定执行
    css 图片垂直居中总结
    JS 面向对象随笔
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9587865.html
Copyright © 2020-2023  润新知