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

    [POI2008]BLO

    一开始没看懂样例,连去掉的点都算……

    显然如果i不是割点,那么ans[i]=(n-1)*2,

    如果i是割点,ans[i]=将i去掉后生成的联通块大小两两相乘的和加上i本身,但这样并不好算,换一种思路,在求割点时记录搜索树中以x为根的子树大小,

    (式子太长不想打了……)

    #include<iostream>
    #include<cstdio>
    #define int long long
    #define MAXN 100010
    using namespace std;
    struct edge
    {
    	int u,v,nxt;
    	#define u(x) ed[x].u
    	#define v(x) ed[x].v
    	#define n(x) ed[x].nxt
    }ed[MAXN*10];
    int first[MAXN],num_e;
    #define f(x) first[x]
    int n,m;
    inline void add(int u,int v)
    {
    	++num_e;
    	u(num_e)=u;
    	v(num_e)=v;
    	n(num_e)=f(u);
    	f(u)=num_e;
    }
    int dfn[MAXN],low[MAXN],size[MAXN],cnt,root;
    bool iscut[MAXN];
    int ans[MAXN];
    void tarjan(int x)
    {
    	dfn[x]=low[x]=++cnt;
    	int flag=0,sum=0;size[x]=1;
    	for(int i=f(x);i;i=n(i))
    	if(!dfn[v(i)])
    	{
    		tarjan(v(i)),low[x]=min(low[x],low[v(i)]);
    		size[x]+=size[v(i)];
    		if(low[v(i)]>=dfn[x])
    		{
    			flag++;
    			ans[x]+=size[v(i)]*(n-size[v(i)]);sum+=size[v(i)];
    			if(x!=root || flag>1)iscut[x]=1;	
    		}
    	}
    	else low[x]=min(low[x],dfn[v(i)]);
    	if(iscut[x])ans[x]+=(n-sum-1)*(sum+1)+n-1;
    	else        ans[x] =(n-1)*2;
    }
    signed main()
    {
    	scanf("%lld%lld",&n,&m);
    	int a,b;
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%lld%lld",&a,&b);
    		if(a!=b)add(a,b);add(b,a);
    	}
    	for(int i=1;i<=n;i++)
    		if(!dfn[i]){root=i;tarjan(i);}
    	for(int i=1;i<=n;i++)
    		printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    swift基本数据类型的使用
    宏定义单例类
    开发必备宏定义大全
    GUI02
    GUI01
    浅谈代码块的加载顺序
    Java里的多态
    在java中this和super的使用
    冒泡排序的简单优化
    命令行传参和不定传参
  • 原文地址:https://www.cnblogs.com/Al-Ca/p/11181966.html
Copyright © 2011-2022 走看看