1. 程式人生 > 實用技巧 >LuoguP3469 [POI2008]BLO-Blockade

LuoguP3469 [POI2008]BLO-Blockade

題面


分析

對每個點的貢獻進行分析:如果這個點不是割點,那麼去掉這個點圖仍然聯通,減少的訪問僅為這個點和其他點之間的聯絡,也就是\(2*(n-1)\)。如果這個點是割點,那麼去除之後圖會變成多個聯通塊。設第\(i\)個聯通塊的大小為\(size_i\),易知聯通塊之間減少的聯絡是\(\Sigma_i\Sigma_j size_isize_j\)。對這個式子做變形,得到\(\Sigma_i size_i(n-size_i-1)\)。於是可以在tarjan的同時求出這個值。把所有貢獻加一起就好了。

程式碼

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {
    
    template<typename T>inline void read (T &x) {
        x=0;T f=1;char c=getchar();
        for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
        for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    template<typename T>inline void write (T x) {
        if (x<0) putchar('-'),x=-x;
        if (x>=10) write(x/10);
        putchar(x%10+'0');
    }
    
}

using namespace StandardIO;

namespace Fate {
#define int long long
	const int N=500500;
	
	int n,m;
	int cnt;
	int head[N];
	struct node {
		int to,next;
	} edge[N<<1];
	int index;
	int dfn[N],low[N],size[N],cut[N];
	int ans[N];
	
	inline void add (int a,int b) {
		edge[++cnt].to=b,edge[cnt].next=head[a],head[a]=cnt;
	}
	void tarjan (int now) {
		int tmp=0;size[now]=1,dfn[now]=low[now]=++index;
		for (register int i=head[now]; i; i=edge[i].next) {
			int to=edge[i].to;
			if (!dfn[to]) {
				tarjan(to);
				size[now]+=size[to];
				low[now]=min(low[now],low[to]);
				if (dfn[now]<=low[to]) {
					ans[now]+=tmp*size[to];
					tmp+=size[to];
				} 
			} else {
				low[now]=min(low[now],dfn[to]);
			}
		}
		ans[now]+=tmp*(n-tmp-1);
	}
    
    inline void Stay_Night () {
    	read(n),read(m);
    	for (register int i=1; i<=m; ++i) {
    		int x,y;
    		read(x),read(y);
    		add(x,y),add(y,x); 
		}
		tarjan(1);
		for (register int i=1; i<=n; ++i) {
			write((ans[i]+n-1)*2),putchar('\n');
		}
    }
#undef int  
}

int main () {
    Fate::Stay_Night();
}