zoukankan      html  css  js  c++  java
  • 【2020小米网络选拔赛D Router Mesh】Tarjan求每个点属于哪几个点双连通分量

    【2020小米网络选拔赛D Router Mesh Tarjan求每个点属于哪几个点双连通分量】求删掉一个点后的连通块个数,对每个点进行一次询问

    传送门

    题意

    给一个无向图,对每一个结点做一个询问,询问为,若删掉该点(及所有与其相关的连边),整个图有几个连通块?

    题解

    用Tarjan算法的思路来写,dfn[i]代表结点 i 的dfs序,low[i]代表从结点 i dfs下去能到达的dfn值最小的结点的dfn值。若u为当前结点,v为一个u的未被访问过的子节点,若对 v dfs完毕后,得到 low[v] >= dfn[u]则说明从u的父亲结点,经过u能够到达v,如果把结点u删掉,则不能到达结点v了。这就相当于删去结点u时,u的父亲结点与结点v会被分成两个连通块,即这两部分无法相互到达,因此只需要数一下对于结点u,它有多少个儿子结点v,满足low[v]>=dfn[u],当然其实u的父亲结点也算是一个儿子节点,因此需要+1表示算上父亲节点。但每次dfs的起点是没有父亲节点的,所以不需要+1.

    综上所述,删去一个结点u会造成怎样的影响呢?假设删去结点u会增加ans[u]个连通块,这个无向图初始包含m个连通块,这个节点原来是属于1个连通块的,它删去后会增加ans[u]个连通块,那么删去这个结点后连通块的数量应为m-1+ans[u]。

    代码

    /****************************
    * Author : W.A.R            *
    * Date : 2020-10-11-17:19   *
    ****************************/
    /*
    */
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<stack>
    #include<string>
    #include<set>
    #define IOS ios::sync_with_stdio(false)
    #define show(x) std:: cerr << #x << " = " << x << std::endl;
    #define mem(a,x) memset(a,x,sizeof(a))
    #define Rint register int
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+10;
    const int maxm=2e6+10;
    const ll mod=1e9+7;
    const double PI=acos(-1.0);
    const double eps=1e-7;
    ll qpow(ll a,ll n){a%=mod;ll ans=1;while(n){if(n%2)ans=ans*a%mod;n/=2;a=a*a%mod;}return ans;}
    int dcmp(double x){if(fabs(x)<eps)return 0;if(x>0)return 1;return -1;}
    /**
    ll fac[maxn],invFac[maxn],mi[maxn],n,sum;
    ll C(ll n,ll m){if(m>n||m<0)return 0;return fac[n]*invFac[n-m]%mod*invFac[m]%mod;}
    void Init(){
    	fac[0]=1;mi[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
    	invFac[n]=qpow(fac[n],mod-2);
    	for(int i=n-1;i>=0;i--)invFac[i]=invFac[i+1]*(i+1)%mod;
    	for(int i=1;i<=n;i++)mi[i]=mi[i-1]*2%mod;
    }
    */
    namespace Fast_IO{
        const int MAXL((1 << 18) + 1);int iof, iotp;
        char ioif[MAXL], *ioiS, *ioiT, ioof[MAXL],*iooS=ioof,*iooT=ioof+MAXL-1,ioc,iost[55];
        char Getchar(){
            if (ioiS == ioiT){
                ioiS=ioif;ioiT=ioiS+fread(ioif,1,MAXL,stdin);return (ioiS == ioiT ? EOF : *ioiS++);
            }else return (*ioiS++);
        }
        void Write(){fwrite(ioof,1,iooS-ioof,stdout);iooS=ioof;}
        void Putchar(char x){*iooS++ = x;if (iooS == iooT)Write();}
        inline int read(){
            int x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
    		if(ioc==EOF)exit(0);
            for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
        }
        inline long long read_ll(){
            long long x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
    		if(ioc==EOF)exit(0);
            for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
        }
        template <class Int>void Print(Int x, char ch = ''){
            if(!x)Putchar('0');if(x<0)Putchar('-'),x=-x;while(x)iost[++iotp]=x%10+'0',x/=10;
            while(iotp)Putchar(iost[iotp--]);if (ch)Putchar(ch);
        }
        void Getstr(char *s, int &l){
            for(ioc=Getchar();ioc==' '||ioc=='
    '||ioc=='	';)ioc=Getchar();
    		if(ioc==EOF)exit(0);
            for(l=0;!(ioc==' '||ioc=='
    '||ioc=='	'||ioc==EOF);ioc=Getchar())s[l++]=ioc;s[l] = 0;
        }
        void Putstr(const char *s){for(int i=0,n=strlen(s);i<n;++i)Putchar(s[i]);}
    } // namespace Fast_IO 
    using namespace Fast_IO;
    struct Edge{int to,nxt;}e[maxn*2];
    int head[maxn],dfn[maxn],low[maxn],ans[maxn],ct,cnt,now;
    void addE(int u,int v){e[++ct].to=v;e[ct].nxt=head[u];head[u]=ct;}
    void Tarjan(int u){
    	dfn[u]=low[u]=++cnt;
    	ans[u]=u!=now;
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(!dfn[v]){
    			Tarjan(v);
    			low[u]=min(low[u],low[v]);
    			ans[u]+=(dfn[u]<=low[v]);
    		}
    		else low[u]=min(low[u],dfn[v]);
    	}
    }
    int main(){
    	int n,m;scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++){
    		int u,v;scanf("%d%d",&u,&v);
    		addE(u,v);addE(v,u);
    	}
    	int C=0;
    	for(int i=1;i<=n;i++)if(!dfn[i])now=i,Tarjan(i),C++;
    	for(int i=1;i<=n;i++)printf("%d%c",C+ans[i]-1,i==n?'
    ':' ');
    	return 0;
    }
    
  • 相关阅读:
    Linux 系统中用户切换(su user与 su
    linux 用户打开进程数和文件数调整
    hive sql 语法详解
    iOS
    iOS
    MySQL的事务的处理
    iOS
    iOS AOP编程思想及实践
    iOS 静态库和动态库(库详解)
    iOS 沙盒目录结构及正确使用
  • 原文地址:https://www.cnblogs.com/wuanran/p/13874624.html
Copyright © 2011-2022 走看看