P3469 [POI2008]BLO-Blockade【题解】

我花了 45 m i n 45min 45min A A A掉了 P O I \red{POI} POI的题!

难度: N O I / N O I + / C T S C ( b u s h i ) {\color{blue}{NOI/NOI+/CTSC}(bushi)} NOI/NOI+/CTSC(bushi)
毕竟也是人家国赛的题,刚拿道题觉得套板子就可以了,没想到细节有 亿 点 点 \color{Red}{亿点点} 亿
题意:

给你一个无向图 G G G,已知 G G G是联通的,求当把每个点封锁时,途中有多少点对 ( u , v ) (u,v) (u,v)不能相互抵达。

第一个坑点来了:细读题目,发现 ( u , v ) (u,v) (u,v)是有序的!也即 ( u , v ) (u,v) (u,v) ( v , u ) (v,u) (v,u)不算同一个点对!

画个图手玩一下可以发现,我们应该对封锁的结点 S S S进行讨论。分两种情况:

1. S is a cut-vertex. ⁡ 1. \operatorname{S\space is\space a\space cut-vertex.} 1.S is a cut-vertex.
2. S   i s n ′ t   a   c u t - v e r t e x . ⁡ 2.\operatorname{S\space isn't\space a\space cut-vertex.} 2.S isnt a cut-vertex.

我们不妨设图 G G G节点数为 ∣ G ∣ |G| G,对于一个点 S S S,问题的答案为 f ( s ) f(s) f(s).若 S S S为一个割点,我们设它将图分成了 k k k个连通块,分别为 S i S_i Si, i ∈ [ 1 , k ] i\in[1,k] i[1,k].则答案为:

f ( S ) { 2 × ( ∣ G ∣ − 1 ) ; S   i s n ′ t   a   c u t - v e r t e x . ⁡ 2 × ( ∣ G ∣ − 1 ) + ∑ i = 1 k ∑ j = i k ∣ S i ∣ × ∣ S j ∣ ; S is a cut-vertex. ⁡ f(S)\begin{cases} 2\times(|G|-1); \operatorname{S\space isn't\space a\space cut-vertex.}\\ 2\times(|G|-1)+\sum\limits_{i=1}^{k}\sum\limits_{j=i}^{k}|S_i|\times |S_j|; \operatorname {S\space is\space a\space cut-vertex.} \end{cases} f(S)2×(G1);S isnt a cut-vertex.2×(G1)+i=1kj=ikSi×Sj;S is a cut-vertex.
第一种情况可以 O ( 1 ) O(1) O(1)地算出来,第二种情况 ∣ S i ∣ |S_i| Si的值可以在 t a r j a n tarjan tarjan的时候顺便算出来。

记 得 开 L o n g   L o n g ! 记得开{\color{Blue}{Long\space Long}}! Long Long!

R e   C o d e : {\color{SpringGreen}{\purple{Re}\space Code:}} Re Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5; 
typedef long long LL;

int n,m,root,v[maxn],tag[maxn],Size[maxn];
int id,dfn[maxn],low[maxn];
bool cut[maxn];
LL ans[maxn];
vector<int> ver[maxn];

inline void read()
{
    
    
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
    
    
		int u,v;
		cin>>u>>v;
		ver[u].push_back(v);
		ver[v].push_back(u);  
	}
}

inline void tarjan(int x)
{
    
    
	low[x]=dfn[x]=++id;
	Size[x]=1;
	int flag=0,sum=0;
	for(int y=0;y<ver[x].size();y++)
	{
    
    
		int t=ver[x][y];
		if(!dfn[t])
		{
    
    
			tarjan(t);
			Size[x]+=Size[t];
			low[x]=min(low[x],low[t]);
			if(low[t]>=dfn[x])
			{
    
    
				flag++;
				ans[x]+=(LL)Size[t]*(n-Size[t]); 
				sum+=Size[t];
				if(x!=1||flag>1) cut[x]=true;
			}
		}
		else
		{
    
    
			low[x]=min(low[x],dfn[t]);
		}
	}
	if(cut[x])
		ans[x]+=(LL)(n-sum-1)*(sum+1)+(n-1);
	else
		ans[x]=2*(n-1);	
}


int main()
{
    
    
	read();
	tarjan(1);
	for(int i=1;i<=n;i++)
	{
    
    
		cout<<ans[i]<<endl;
	}
	return 0;
}

A C   C o d e : \green{AC\space Code:} AC Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
inline int read()
{
    
    
	int x=0,t=1;char ch=getchar();
	while(ch>'9'||ch<'0'){
    
    if(ch=='-')t=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*t;
}
int n,m,head[maxn],num=0;
int dfn[maxn],low[maxn],size[maxn],tot=0;
long long ans[maxn];
bool cut[maxn];
struct node{
    
    
	int v,nex;
}e[maxn];
void add(int u,int v)
{
    
    
	e[++num].v=v;
	e[num].nex=head[u];
	head[u]=num;
}
void tarjan(int u)
{
    
    
	dfn[u]=low[u]=++tot;
	size[u]=1;
	int flag=0,sum=0;
	for(int i=head[u];i;i=e[i].nex)
	{
    
    
		int v=e[i].v;
		if(!dfn[v])
		{
    
    
			tarjan(v);
			size[u]+=size[v];
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u])
			{
    
    
				ans[u]+=(long long)size[v]*(n-size[v]);
				sum+=size[v];
				flag++;
				if(u!=1||flag>1) cut[u]=true;
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(!cut[u]) ans[u]=2*(n-1);
	else ans[u]+=(long long)(n-sum-1)*(sum+1)+(n-1);
}
int main()
{
    
    
	n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
    
    
		int x,y;
		x=read(),y=read();
		add(x,y),add(y,x);
	}
	tarjan(1);
	for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_62444770/article/details/120618370