• #Kruskal,可撤销并查集#CF891C Envy


    题目

    给出一个 (n) 个点 (m) 条边的无向图,每条边有边权,共 (Q) 次询问,

    每次给出 (k_i) 条边,问这些边能否同时在一棵最小生成树上。


    分析

    考虑最小生成树选择的边权的种类和数量是固定的,

    那么可以按照边权排序,小于该边权的边已经用来构建MST,只需要考虑该边权的边。

    按照不同的询问把边加进去看看是否不成环,处理一个询问再把刚刚加入的边撤销。


    代码

    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <algorithm>
    #define rr register
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2?EOF:*p1++)
    using namespace std;
    const int N=500011; struct rec{int x,y,w;}e[N]; vector<rec>K[N]; char buf[1<<21],*p1,*p2;
    int f[N],dep[N],n,m,Q,ans[N],stac[N],tac[N],stad[N*10],tad[N*10],tot,tod;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    bool cmp(rec x,rec y){return x.w<y.w;}
    inline signed getf(int u){
    	if (f[u]==u) return u;
    	rr int U=getf(f[u]);
    	if (dep[u]<dep[f[u]]+1){
    		stad[++tod]=u,tad[tod]=dep[u];
    		dep[u]=dep[f[u]]+1;
    	}
    	return U;
    }
    inline bool Merge(int x,int y){
    	rr int fa=getf(x),fb=getf(y);
    	if (fa==fb) return 0;
    	if (dep[fa]>dep[fb]) fa^=fb,fb^=fa,fa^=fb;
    	if (dep[fa]==dep[fb])
    		stad[++tod]=fb,tad[tod]=dep[fb]++;
    	stac[++tot]=fa,tac[tot]=f[fa],f[fa]=fb;
    	return 1;
    }
    signed main(){
    	n=iut(),m=iut();
    	for (rr int i=1;i<=m;++i)
    	    e[i]=(rec){iut(),iut(),iut()};
    	for (rr int i=1;i<=n;++i) dep[i]=1,f[i]=i;
    	Q=iut();
    	for (rr int i=1;i<=Q;++i)
    	for (rr int j=iut();j;--j){
    		rr int t=iut();
    	    K[e[t].w].push_back((rec){e[t].x,e[t].y,i});
    	}
    	for (rr int i=1;i<=Q;++i) ans[i]=1;
        sort(e+1,e+1+m,cmp);
        for (rr int l=1,r;l<=m;l=r+1){
        	for (r=l;e[r].w==e[l].w;++r); --r;
        	rr int len=K[e[l].w].size();
    		tot=tod=0;
        	for (rr int i=0;i<len;++i){
        		rr rec t=K[e[l].w][i];
        		if (!ans[t.w]) continue;
        		if (i>0&&t.w!=K[e[l].w][i-1].w){
        			for (;tot;--tot) f[stac[tot]]=tac[tot];
        			for (;tod;--tod) dep[stad[tod]]=tad[tod];
    			}
    			ans[t.w]&=Merge(t.x,t.y);
    		}
    		for (rr int i=l;i<=r;++i) Merge(e[i].x,e[i].y);
    	}
    	for (rr int i=1;i<=Q;++i) puts(ans[i]?"YES":"NO");
    	return 0;
    }
    
  • 相关阅读:
    write to logfile
    open and read a file content to a variable
    strategy
    Android 开机启动程序
    消息队列
    卡机音乐功能实现
    Android 2.0 开机动画文件分析
    多线程实例
    消息队列
    多线程实例
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/15333597.html
Copyright © 2020-2023  润新知