zoukankan      html  css  js  c++  java
  • 并查集练习

    1. luogu P4185 MooTube

    大意: 给定树, 定义两点距离为两点树链上的最小边权, m个询问(k,v), 求到v距离>=k的点的个数.

    离线后用并查集不断添边即可, 在线的话可以用kruskal重构树

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #define pb push_back
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    using namespace std;
    
    const int N = 1e5+10;
    int n, q, s[N], cnt[N], ans[N];
    struct _ {int u,v,w;} e[N];
    struct __ {int k,v,id;} qry[N];
    int Find(int x) {return s[x]?s[x]=Find(s[x]):x;}
    void add(int x, int y) {
    	x = Find(x), y = Find(y);
    	if (x!=y) s[x]=y,cnt[y]+=cnt[x];
    }
    int main() {
    	scanf("%d%d", &n, &q);
    	REP(i,1,n-1) scanf("%d%d%d", &e[i].u,&e[i].v,&e[i].w);
    	sort(e+1,e+n,[](_ a,_ b){return a.w>b.w;});
    	REP(i,1,q) scanf("%d%d", &qry[i].k, &qry[i].v),qry[i].id=i;
    	sort(qry+1,qry+1+q,[](__ a,__ b){return a.k>b.k;});
    	REP(i,1,n) cnt[i] = 1;
    	int now = 1;
    	REP(i,1,q) {
    		while (now<=n-1&&e[now].w>=qry[i].k) { 
    			add(e[now].u,e[now].v),++now;
    		}
    		ans[qry[i].id] = cnt[Find(qry[i].v)];
    	}
    	REP(i,1,q) printf("%d
    ", ans[i]-1);
    }
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #define pb push_back
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    using namespace std;
    
    const int N = 1e5+10;
    int n, q, tot, s[N<<1], val[N<<1];
    vector<int> g[N<<1];
    int sz[N<<1], fa[N<<1][20];
    struct _ {int u,v,w;} e[N];
    int Find(int x) {return s[x]?s[x]=Find(s[x]):x;}
    void dfs(int x, int f) {
    	sz[x] = 1;
    	fa[x][0] = f;
    	REP(i,1,19) fa[x][i]=fa[fa[x][i-1]][i-1];
    	for (int y:g[x]) dfs(y,x),sz[x]+=sz[y];
    }
    int main() {
    	scanf("%d%d", &n, &q);
    	REP(i,1,n-1) scanf("%d%d%d", &e[i].u,&e[i].v,&e[i].w);
    	sort(e+1,e+n,[](_ a,_ b){return a.w>b.w;});
    	int tot = n;
    	REP(i,1,n-1) {
    		int u=Find(e[i].u),v=Find(e[i].v);
    		s[u] = s[v] = ++tot, val[tot]=e[i].w;
    		g[tot].pb(u), g[tot].pb(v);
    	}
    	dfs(tot,0);
    	REP(i,1,q) {
    		int k, v;
    		scanf("%d%d", &k, &v);
    		PER(i,0,19) if (val[fa[v][i]]>=k) v=fa[v][i];
    		printf("%d
    ", sz[v]>>1);
    	}
    }
    

    2. hdu 3938 Portal

    大意: 无向图, 求有多少条路径, 满足路径上边权的最大值<=L.

    可以离线后用并查集算出每条边的贡献.

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    #define x first
    #define y second
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    
    const int N = 1e6+10;
    int n, m, q, s[N], sz[N];
    struct _ {int u,v,w;} e[N];
    pii a[N];
    ll ans[N];
    int Find(int x) {return s[x]?s[x]=Find(s[x]):x;}
    ll add(int x, int y) {
    	x=Find(x), y=Find(y);
    	if (x==y) return 0;
    	ll t = (ll)sz[x]*sz[y];
    	s[x] = y, sz[y] += sz[x];
    	return t;
    }
    
    void work() {
    	REP(i,1,m) scanf("%d%d%d", &e[i].u,&e[i].v,&e[i].w);
    	sort(e+1,e+1+m,[](_ a,_ b){return a.w<b.w;});
    	REP(i,1,q) scanf("%d",&a[i].x),a[i].y=i;
    	sort(a+1,a+1+q);
    	REP(i,1,n) sz[i] = 1, s[i] = 0;
    	int now = 1;
    	REP(i,1,q) {
    		ans[a[i].y] = ans[a[i-1].y];
    		while (now<=m&&e[now].w<=a[i].x) { 
    			ans[a[i].y] += add(e[now].u,e[now].v);
    			++now;
    		}
    	}
    	REP(i,1,q) printf("%lld
    ",ans[i]);
    }
    
    int main() {
    	for (; ~scanf("%d%d%d", &n, &m, &q); ) work();
    }
    

    3. CF 891C Envy

    大意: 给定无向图, 每次询问给出一个边集S, 求判断S中的所有边是否能在某个最小生成树上.

    对于一条边(u,v,w), 若(u,v,w)能在一个MST上, 那么必须满足所有<w的边权不能连通点u和v, 所有边集离线后跑一次kruskal即可. 

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    using namespace std;
    
    const int N = 1e6+10;
    int n, m, q, tot, clk;
    int ans[N], fa1[N], fa2[N], c[N];
    struct _ {
    	int u,v,w,id;
    	bool operator < (const _ &rhs) const {
    		return w<rhs.w||w==rhs.w&&id<rhs.id;
    	}
    } e[N], s[N];
    int Find1(int x) {return fa1[x]?fa1[x]=Find1(fa1[x]):x;}
    void add(int x, int y) {
    	x=Find1(x),y=Find1(y);
    	if (x!=y) fa1[x]=y;
    }
    int Find2(int x) {
    	if (c[x]!=clk) fa2[x]=fa1[x],c[x]=clk;
    	return fa2[x]?fa2[x]=Find2(fa2[x]):x;
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	REP(i,1,m) scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    	scanf("%d", &q);
    	REP(i,1,q) {
    		int k, t;
    		scanf("%d", &k);
    		REP(j,1,k) {
    			scanf("%d", &t);
    			++tot, s[tot] = e[t], s[tot].id = i;
    		}
    	}
    	sort(e+1,e+1+m), sort(s+1,s+1+tot);
    	int now = 1;
    	for (int i=1; i<=tot; ) {
    		while (e[now].w<s[i].w) add(e[now].u,e[now].v),++now;
    		++clk;
    		for (int t=s[i].w; s[i].w==t; ++i) {
    			if (s[i].id!=s[i-1].id) ++clk;
    			int u=Find2(s[i].u),v=Find2(s[i].v);
    			if (u==v) ans[s[i].id]=1;
    			else fa2[u]=v;
    		}
    	}
    	REP(i,1,q) puts(ans[i]?"NO":"YES");
    }
    
  • 相关阅读:
    php学习记录 易混淆
    自己学习smarty的一些代码 和记录
    Java 死锁
    Java多线程下单例
    Java 线程安全问题
    Java 线程状态
    Java 创建线程
    Java clone() 浅拷贝 深拷贝
    Java 多线程
    Java throw try catch
  • 原文地址:https://www.cnblogs.com/uid001/p/10698311.html
Copyright © 2011-2022 走看看