zoukankan      html  css  js  c++  java
  • P3469 [POI2008]BLO-Blockade

    tarjan 割点
    P3469 [POI2008]BLO-Blockade

    问题描述

    B 城有 (n) 个城镇,(m) 条双向道路。
    每条道路连结两个不同的城镇,没有重复的道路,所有城镇连通。
    把城镇看作节点,把道路看作边,容易发现,整个城市构成了一个无向图。

    输入格式

    第一行包含两个整数 (n)(m)
    接下来 (m) 行,每行包含两个整数 (a)(b),表示城镇 (a)(b) 之间存在一条道路。

    输出格式

    输出共 (n) 行,每行输出一个整数。
    (i) 行输出的整数表示把与节点 (i) 关联的所有边去掉以后(不去掉节点 (i) 本身),无向图有多少个有序点 ((x,y)),满足 (x)(y) 不连通。

    数据范围

    (nle 100000)(mle500000)


    先用 tarjan 求出割点,对于非割点,除它以外的点的连通性不受他的影响,所以只有它与其它点会不连通,答案是 (2(n-1))

    对于那些是割点的点,它会把整个图分成若干个联通块(假设是 (k) 个),那么不连通的点对数就是

    [sum_{i=1}^k a_icdot (n-a_i)+2(n-1) ]

    就是说每个联通块的点数((a_i)),都与其它点,除去当前这个割点((n-a_i-1)),不相连通
    当然这些联通块都是不包含当前这个割点的

    那么如何求这些联通块?
    tarjan 的时候,对于有向边 ((u,v))(low_vge dfn_u) 就说明如果不经过 (u)(v) 和它后面的点就不能回到 (u) 之前,那么搜索树中以 (v) 为根的子树,正是一个这样的联通快
    假设这个搜索树子树的大小是 (size_v),那么这个 (size_v) 就是 (a_i),直接加到答案里就行了
    (sum_{(u,v)}size_v=sum),则还应该有一个大小为 (n-sum-1) 的联通块,就是在搜索树中从 (u)“往上”有一个联通块,那么答案还要再加 ((n-sum-1)cdot (n-(n-sum-1)-1)=sum(n-sum-1))

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    //tarjan 割点 
    #define N 100006
    #define M 1000006
    int n,m;
    int fir[N],nex[M],to[M],tot;
    int cut[N],dfn[N],low[N],dfscnt;
    LL ans[N];
    inline void add(int x,int y){
    	to[++tot]=y;
    	nex[tot]=fir[x];fir[x]=tot;
    }
    int tarjan(int u,int fa){//return size of subtree u
    	dfn[u]=low[u]=++dfscnt;
    	int children=0,size=1,size_v,sum=0;
    	for(reg int v,i=fir[u];i;i=nex[i]){
    		v=to[i];
    		if(!dfn[v]){
    			size_v=tarjan(v,fa);
    			size+=size_v;
    			low[u]=std::min(low[u],low[v]);
    			if(low[v]>=dfn[u]){
    				sum+=size_v;ans[u]+=(LL)size_v*(n-size_v-1);
    				if(u!=fa) cut[u]=1;
    			}
    			children++;
    		}
    		else low[u]=std::min(low[u],dfn[v]);
    	}
    	ans[u]+=(LL)sum*(n-sum-1);
    	if(children>1&&u==fa) cut[u]=1;
    //		std::printf("u : %d  size : %d ans : %d
    ",u,size,ans[u]);
    	return size;
    }
    int main(){
    	n=read();m=read();
    	for(reg int u,v,i=1;i<=m;i++){
    		u=read();v=read();
    		add(u,v);add(v,u);
    	}
    	tarjan(1,1);
    	for(reg int i=1;i<=n;i++)
    		std::printf("%lld
    ",(n-1)*2+cut[i]*ans[i]);
    //		
    //		EN;EN;
    //		for(reg int i=1;i<=n;i++) std::printf("dfn : %d  low : %d  size : %d
    ",dfn[i],low[i],size[i]);
    	return 0;
    }
    
  • 相关阅读:
    使用gitblit搭建一个简单的局域网服务器
    Git的一些基本操作和命令
    oracle 常用函数
    Windows 下用 gogs 配置局域网 git server
    慎用 new、delete
    探究functools模块wraps装饰器的用途
    处理QMenu的triggered信号时遇到的一个问题
    浅析MySQL中exists与in的使用
    java-工具类-读取配置文件
    Java web的基本概念
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12742176.html
Copyright © 2011-2022 走看看