• BZOJ1123: [POI2008]BLO


    BZOJ1123: [POI2008]BLO

    Description

    Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。

    Input

    输入n<=100000 m<=500000及m条边

    Output

    输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。

    Sample Input

    5 5
    1 2
    2 3
    1 3
    3 4
    4 5

    Sample Output

    8
    8
    16
    14
    8

    题解Here!

    首先可以对任意一个节点$i$进行讨论:
    1. 假如$i$不是割点,那么这个图只有$i$是独立在外面的。
    由于求的是有序点对,所以除了$i$以外的$n-1$个点作为一个大的连通图对$i$加边,即为$2 imes(n-1)$对。
    2. 假如$i$是割点,那么会把图分为$x$个连通块以及$i$本身。
    由于$Tarjan$在求割点的过程中是一棵搜索树往下遍历,所以除了它和它的子树外,还会有其他剩余点共同构成另一个连通块。
    设$i$所有子树的和为$w$,第$i$个子树的节点总数为$size[i]$,点对的数量便为:
    $$sum_{i=1}^xsize[i] imes(n-size[x])+(n-1)+(1+w) imes(n-w-1)$$
    所以在求割点的过程中每遇到一个$low[v]>=dfn[u]$便把对数加上$size[i] imes(n-size[i])$。
    最后假如不是割点那直接把对数更新为$2 imes(n-1)$是割点则加上$n-1+(n-w-1) imes(w+1)$。
    最后遍历输出答案即可。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define MAXN 100010
    using namespace std;
    int n,m,c=1,d=1;
    int head[MAXN],deep[MAXN],low[MAXN],size[MAXN];
    bool cut[MAXN];
    long long ans[MAXN];
    struct Edge{
    	int next,to;
    }a[MAXN*10];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline void add_edge(int x,int y){
    	a[c].to=y;a[c].next=head[x];head[x]=c++;
    	a[c].to=x;a[c].next=head[y];head[y]=c++;
    }
    void dfs(int x){
    	int s=0,w=0;
    	deep[x]=low[x]=d++;
    	size[x]=1;
    	for(int i=head[x];i;i=a[i].next){
    		int v=a[i].to;
    		if(!deep[v]){
    			dfs(v);
    			low[x]=min(low[x],low[v]);
    			size[x]+=size[v];
    			if(low[v]>=deep[x]){
    				ans[x]+=1LL*size[v]*(n-size[v]);
    				w+=size[v];
    				s++;
    				if(x!=1||s>=2)cut[x]=true;
    			}
    		}
    		else low[x]=min(low[x],deep[v]);
    	}
    	if(!cut[x])ans[x]=2*(n-1);
    	else ans[x]+=1LL*(n-w-1)*(w+1)+n-1;
    }
    void work(){
    	int x,y;
    	n=read();m=read();
    	for(int i=1;i<=m;i++){
    		x=read();y=read();
    		add_edge(x,y);
    	}
    	dfs(1);
    	for(int i=1;i<=n;i++)printf("%lld
    ",ans[i]);
    }
    int main(){
    	work();
        return 0;
    }
    
  • 相关阅读:
    自定义实现wcf的用户名密码验证
    EF6:编写你自己的code first 数据迁移操作(睡前来一篇,翻译的)
    .net 连接Redis
    idea external libraries 只有jdk问题
    MAC vim安装gruvbox主题
    Mac gitk安装与优化
    spring security 4 filter 顺序及作用
    mysql 采样查询 / 间隔查询 / 跳跃查询的两种实现思路
    nginx warn an upstream response is buffered to a temporary file /var/cache/nginx/proxy_temp/ while reading upstream
    nginx日志 logrotate配置
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9840474.html
Copyright © 2020-2023  润新知