• SP15577 STC10


    写在前面

    这几天一直在做 (Tarjan) 算法,也恰好遇上这一个题目,那就做一做吧,看了一些题解也不多,就交一下

    题面大意

    3469雷同了,这里也还是说一下吧,给定一张无向图,求每个点被封锁之后有多少个有序点对 ((x,y) (x ot =y,1<=x,y<=n)) 满足 (x) 无法到达(y) ,

    思路

    enter image description here

    然后手动模拟一下敲点,把节点 (1) 敲掉,我们就可以发现 ((1,2),(2,1)……(1,5)(5,1)) 这8个有序数对是无法相互到达的,所以我们可以得出一个结论,当节点 (x) 不是一个割点的时候,我们删去它,它贡献的有序点对数为 (2 imes(n - 1)) ,(n-1)就是除了自己,都不能到达了,但是这是一个有序数对,无向图,所以要 ( imes 2)

    当我们敲掉节点 (3) 的时候,我们也尝试用上面的,首先就是到达节点 (3) 的有序数对都不能到达了,那么就是 (2 imes (5 - 1)) 了,但是我们发现,由于节点 (3) 是一个割点,我们把它删除以后,$(1,4) , (4,1)……(2 , 5) (5,2) $,都不能到达了,式子化简出来就是这么式子

    [sum_{i =1}^{top} sum_{j=1}^{back}1 ]

    什么意思,就是(top)删去节点(3)之后,上面的总共几个节点,对应着上面的(1,2)(back)就是下面几个节点,对应着上面的(4,5),然后这个式子因为里面是(1)的总和,所以,我们就可以提出来,也就是

    [top imes back ]

    (top,back)还是上面的意思。

    综上,我们就找出来了这几个点的情况,

    当它是割点的时候,贡献是它的子树的大小的乘积

    当它不是割点的时候,贡献是 ((n-1) imes 2)

    其实这个题还可以加强一下,是图不连通的情况,那么不是割点的节点的贡献就变成 ((len_i - 1) imes 2) ,其中 (len_i) 表示的是节点 (i) 所处的连通块的大小。

    ( ext{code})

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <stack>
    #define int long long 
    using namespace std ;
    const int kmaxn = 5e6 + 10 ; 
    inline int read()
    {
    	int x = 0 , f = 1 ; char ch = getchar() ; 
    	while(!isdigit(ch)) { if(ch == '-') f = - 1 ; ch = getchar() ; }
    	while( isdigit(ch)) { x = x * 10 + ch - '0' ; ch = getchar() ; }
    	return x * f ;
    }
    struct node 
    {
    	int nxt , v , u , val ;
    }e[kmaxn << 1] ; 
    int tot , h[kmaxn << 1] ; 
    void add(int u , int v )
    {
    	e[++tot].nxt = h[u] ; 
    	e[tot].u = u ; 
    	e[tot].v = v ;
    	h[u] = tot ;
    }
    int sum ,  cnt , n , m ;
    int dfn[kmaxn << 1] , low[kmaxn] , cut[kmaxn] , size[kmaxn] , ans[kmaxn] ; 
    void tarjan(int u, int fa) 
    {
        low[u] = dfn[u] = ++cnt;
        int child = 0 ;
        int sum = 0 ;  
        size[u] = 1 ;
        for (int i = h[u]; i; i = e[i].nxt) 
    	{
            int v = e[i].v;
            if (!dfn[v]) 
    		{
                tarjan(v, u) ;
                size[u] += size[v] ; 
    			low[u] = min(low[u], low[v]);
                if(low[v] >= dfn[u] ) 
    			{
    				cut[u] = 1;
    				sum += size[v]; 
    				ans[u] += size[v] * ( n - size[v] ) ; 
    				if(child >= 2 ||  u != fa) cut[u] = 1;
    			}
                if(u == fa) child ++;
            } 
            else low[u] = min(low[u], dfn[v]);
        }
     	if(!cut[u]) ans[u] = (n - 1) * 2 ;//该点是割点 
     	else ans[u] += (n - sum - 1) * (sum + 1) + (n - 1 ) ;
    }
    signed main()
    {
    	n = read() , m = read() ; 
    	for(int i = 1 ; i <= m ; i++)
    	{
    		int u = read() , v = read() ; 
    		add( u , v ) ; 
    		add( v , u ) ; 
    	}
    	for(int i = 1 ; i <= n ; i++)
    	{
    		if(!dfn[i]) 
    		{
    			tarjan(i , i) ; 
    		}
    	}
    	for(int i = 1 ; i <= n ; i++)
    	{
    		printf("%lld
    " , ans[i]);
    	}
    	return 0 ;
    }
    
  • 相关阅读:
    Linux、CentOS系统下调整home和根分区大小
    Dell服务器Raid卡电池策略调整
    自建Saltstack的repo软件源仓库
    CentOS6.6下DRBD+HeartBeat+NFS配置
    go vendor目录
    cmd/go: unsupported GOOS/GOARCH pair linux /amd64
    linux的单用户模式
    go import导入的理解
    监控系统整合告警平台实现邮件、短信、微信、电话语音和app等多方式报警
    如何以非交互方式为psql指定密码?
  • 原文地址:https://www.cnblogs.com/Zmonarch/p/14368890.html
Copyright © 2020-2023  润新知