• 【openjudge】C15C Rabbit's Festival CDQ分治+并查集


    题目链接:http://poj.openjudge.cn/practice/C15C/

    题意:n 点 m 边 k 天。每条边在某一天会消失(仅仅那一天消失)。问每一天有多少对点可以相互到达。

    解法:开始不会做,参考的YYN的题解:http://blog.csdn.net/u013368721/article/details/45725181

    学习了这种CDQ加并查集的做法,可以说是非常的巧妙了。复杂度可以保证在:O(KlogklogK)的范围。

    //CDQ + DSU
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn = 100010;
    const int maxe = 200010;
    struct edge{
        int u,v,next;
        edge(){}
        edge(int u,int v,int next):u(u),v(v),next(next){}
    }E[maxn*2];
    int n, m, k, head[maxn], edgecnt;
    struct Node{
        int u,v,cntu,cntv,rnku,rnkv;
        Node(){}
        Node(int u,int v,int cntu,int cntv,int rnku,int rnkv):u(u),v(v),cntu(cntu),cntv(cntv),rnku(rnku),rnkv(rnkv){}
    };
    Node S[maxe];
    int cnt[maxn];
    int p[maxn];
    int rnk[maxn];
    int top;
    LL ans;
    void init(){
        top = 0;
        ans = 0;
        edgecnt=0;
        memset(head,-1,sizeof(head));
    }
    void add(int id , int u, int v){
        E[edgecnt] = edge (u, v, head[id]);
        head[id] = edgecnt++;
    }
    int find_set(int x){
        int o = x;
        while(p[o] != o) o = p[o];
        return o;
    }
    void union_set(int l, int r){
        for(int t=l; t<=r; t++){
            for(int i=head[t]; ~i; i=E[i].next){
                int u = find_set(E[i].u);
                int v = find_set(E[i].v);
                if(u == v) continue;
                S[top++] = Node(u, v, cnt[u], cnt[v], rnk[u], rnk[v]);
                ans += (LL)cnt[u] * cnt[v];
                if(rnk[u] <= rnk[v]){
                    rnk[v] = max(rnk[v], rnk[u]+1);
                    p[u] = v;
                    cnt[v] += cnt[u];
                }
                else{
                    p[v] = u;
                    cnt[u] += cnt[v];
                }
            }
        }
    }
    void Back(int x)
    {
        while(top > x){
            --top;
            int u = S[top].u, v = S[top].v;
            ans -= (LL)S[top].cntu*S[top].cntv;
            p[u] = u;
            p[v] = v;
            cnt[u] = S[top].cntu;
            cnt[v] = S[top].cntv;
            rnk[u] = S[top].rnku;
            rnk[v] = S[top].rnkv;
        }
    }
    void CDQ(int l, int r)
    {
        if(l == r){
            printf("%lld
    ", ans);
            return;
        }
        int mid=(l+r)>>1;
        int rtop=top;
        union_set(mid+1,r);
        CDQ(l, mid);
        Back(rtop);
        union_set(l,mid);
        CDQ(mid+1,r);
        Back(rtop);
    }
    int main()
    {
        while(~scanf("%d %d %d", &n,&m,&k))
        {
            init();
            for(int i=1; i<=n; i++){
                p[i]=i;
                cnt[i]=1;
                rnk[i]=0;
            }
            int u, v, c;
            for(int i=1; i<=m; i++){
                scanf("%d %d %d", &u,&v,&c);
                if(c > k){
                    u = find_set(u), v = find_set(v);
                    if(u == v) continue;
                    if(rnk[u]<=rnk[v]){
                        rnk[v]=max(rnk[v],rnk[u]+1);
                        p[u]=v;
                        cnt[v]+=cnt[u];
                    }
                    else{
                        p[v]=u;
                        cnt[u]+=cnt[v];
                    }
                }
                else{
                    add(c, u, v);
                }
            }
            CDQ(1, k);
        }
        return 0;
    }
    
  • 相关阅读:
    centos 7 搭建 LNMP ( Linux+Nginx+MySQL+PHP )
    centos 7 安装 redis-5.0.5
    centos 7 安装 Oracle 12c
    centos 7 SVN安装脚本搭建主从同步灵活切换
    Windwos Java‘bat 环境变量配置脚本
    centso 7 Keepalived 配置脚本
    centos 7 私有云盘 OwnCloud 安装搭建脚本
    Linux fing cd 查找文件/文件夹并进入目录命令
    Linux grep命令 -- 三剑客老三
    基础脚本
  • 原文地址:https://www.cnblogs.com/spfa/p/7358672.html
Copyright © 2020-2023  润新知