zoukankan      html  css  js  c++  java
  • 牛客练习赛71 F-红蓝图 (kruskal重构树 + 线段树合并)

    思路:看到存在删边的维护连通块,首先想到 (kruskal) 重构树,我们单独对红边所构成的图跑一次 (kruskal) ,顺便记录每次询问的是哪个子树,
    并且维护出这颗树的 (dfs) 序,这样我们在处理蓝边所构成的图时,就变成查询对应的连续的点了,现在我们倒着处理蓝边,对每个连通块维护一颗动态开点的权值线段树,
    将这颗线段树中,对应的该连通块中的点的 (dfs) 序赋成 (1) ,连通块合并的时候就可以线段树合并维护。

    #include <bits/stdc++.h>
    using namespace std;
    #define lc (rt << 1)
    #define rc ((rt << 1) | 1)
    #define fi first
    #define se second
    #define pb push_back
    #define pii pair<int, int>
    #define rep(i, l, r) for (int i = (l); i <= (r); ++i)
    #define per(i, r, l) for (int i = (r); i >= (l); --i)
    #define PE(i, u) for (int i = head[u]; i != -1; i = edge[i].next)
    typedef long long LL;
    const int maxn = 3e6 + 20;
    const int mod = 1e9 + 7;
    
    struct Edge
    {
        int u, to, w, next;
    } edge[maxn * 2], a[maxn];
    
    bool cmp1(Edge A, Edge B){
        if(A.w != B.w){
            return A.w < B.w;
        } else {
            return A.next > B.next;
        }
    }
    
    bool cmp2(Edge A, Edge B){
        if(A.w != B.w){
            return A.w < B.w;
        } else {
            return A.next < B.next;
        }
    }
    int k, head[maxn];
    void add(int a, int b){
        edge[k].to = b;
        edge[k].next = head[a];
        head[a] = k++;
    }
    
    int fa[maxn], qur[maxn];
    
    int Find(int x){
        if(x == fa[x]) return x;
        return fa[x] = Find(fa[x]);
    }
    
    int tot;
    int unit(int x, int y){
        x = Find(x), y = Find(y);
        if(x == y) return 0;
        tot++;
        add(tot, x), add(tot, y);
        fa[x] = fa[y] = fa[tot] = tot;
        return 1;
    }
    
    int unit2(int x, int y){
        x = Find(x), y = Find(y);
        if(x == y) return 0;
        return 1;
    }
    
    int dfn[maxn], qle[maxn], qri[maxn], id[maxn], tim;
    void dfs(int u){
        dfn[u] = qle[u] = ++tim;
        id[tim] = u;
        PE(i, u){
            int to = edge[i].to;
            dfs(to);
        }
        qri[u] = tim;
    }
    
    int cntree;
    int root[maxn], tree[maxn << 2], ls[maxn << 2], rs[maxn << 2];
    void Update(int le, int ri, int pos, int &rt){
        if(!rt) rt = ++cntree;
        if(le == ri){
            tree[rt] = 1;
            return ;
        }
        int mid = (le + ri) >> 1;
        if(pos <= mid) Update(le, mid, pos, ls[rt]);
        if(pos > mid) Update(mid + 1, ri, pos, rs[rt]);
        tree[rt] = tree[ls[rt]] + tree[rs[rt]];
    }
    
    int merge(int x, int y){
        if(!x || !y){
        	tree[x | y] = tree[x] + tree[y];
            return x | y;
        }
        // int rt = ++cntree;
        tree[y] = tree[x] + tree[y];
        ls[y] = merge(ls[x], ls[y]);
        rs[y] = merge(rs[x], rs[y]);
        return y;
    }
    int Query(int le, int ri, int L, int R, int rt){
        if(!rt) return 0;
        if(L <= le && ri <= R){
            return tree[rt]; 
        }
        int mid = (le + ri) >> 1;
        int res = 0;
        if(L <= mid) res += Query(le, mid, L, R, ls[rt]);
        if(R > mid) res += Query(mid + 1, ri, L, R, rs[rt]);
        return res; 
    }
    int ans[maxn];
    int main(int argc, char const *argv[])
    {
        int n, m, q;
        scanf("%d%d%d", &n, &m, &q);
        tot = n;
        rep(i, 1, n * 2) head[i] = -1, fa[i] = i;
        rep(i, 1, m){
            int u, v, c;
            scanf("%d%d%d", &u, &v, &c);
            u++, v++;
            a[i] = {u, v, i, c};
        }
        rep(i, 1, q){
            int u, w;
            scanf("%d%d", &u, &w);
            u++;
            a[m + i] = {u, i, w, -1};
        }
        sort(a + 1, a + m + q + 1, cmp1);
        rep(i, 1, m + q){
            if(a[i].next != -1){
                if(a[i].next == 0) unit(a[i].u, a[i].to);
            } else{
                qur[a[i].to] = Find(a[i].u);
            }
        }
        rep(i, 1, tot){
            Find(i);
            if(i == fa[i]){
                dfs(i);
            }
        }
        rep(i, 1, n){
            Update(1, tot, dfn[i], root[i]);
        }
        sort(a + 1, a + m + q + 1, cmp2);
        rep(i, 1, n) fa[i] = i;
        per(i, q + m, 1){
            if(a[i].next != -1){
                if(a[i].next == 1){ 
                    int x = a[i].u, y = a[i].to;
                    if(unit2(x, y)){ // 这里的unit2只是判断是否可以合并,暂时不合并
                        x = Find(x), y = Find(y);
                        root[x] = root[y] = merge(root[x], root[y]);
                        fa[x] = y; // 在这里完成合并
                    }
                }
            } else {
                int u = a[i].u;
                u = Find(u);
                int res = Query(1, tot, qle[qur[a[i].to]], qri[qur[a[i].to]], root[u]);
                ans[a[i].to] = res;
            }
        }
        rep(i, 1, q){
            printf("%d
    ", ans[i]);
        }
        return 0;
    }
    
    // 3 5 2
    // 2 0 1
    // 0 1 1
    // 2 2 0
    // 1 0 0
    // 1 1 1
    // 1 2
    // 2 1
    
    
  • 相关阅读:
    mybatis2入门程序
    mybatis1
    mybeats与jdbc问题分析
    mysqljdbc简单连接释放
    jdbc问题记录
    section,article,div
    HB调试前端开发移动
    HTML,XML,XHTML
    访问地图
    OAuth
  • 原文地址:https://www.cnblogs.com/PCCCCC/p/13803120.html
Copyright © 2011-2022 走看看