3331: [BeiJing2013]压力

3331: [BeiJing2013]压力

LCA+树上差分,和之前类似的题差不多,就是多了个v-dcc缩点,唯一要注意的就是判断是否是割点,对于不是割点的点,如果他是起点或重点,ans++,和差分没有关系,对于割点,则需要用到差分,注意割点与非割点的答案要分开存储,否则会死的。

另外要注意的是数组的大小,开始我因为数组开小了然后MLE了(对,就是这么神奇),因为如果退化成一条链,缩完点后的点数会比缩点前还要多。

#include<iostream>
#include<cstdio>
#include<vector>
#define MAXN 300010
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
	#define u2(x) ed2[x].u
	#define v2(x) ed2[x].v
	#define n2(x) ed2[x].nxt
}ed[MAXN*4],ed2[MAXN*4];
int first[MAXN],num_e;
#define f(x) first[x]
int first2[MAXN],num_e2;
#define f2(x) first2[x]
int n,m,q;

int dfn[MAXN],low[MAXN],num,root;
int stack[MAXN],top,cnt;
bool iscut[MAXN];
vector<int> dcc[MAXN];
void tarjan(int x)
{
	dfn[x]=low[x]=++num;
	stack[++top]=x;
	if(x==root&&!f(x)){dcc[++cnt].push_back(x);return;}
	int flag=0;
	for(int i=f(x);i;i=n(i))
	if(!dfn[v(i)])
	{
		tarjan(v(i));low[x]=min(low[x],low[v(i)]);
		if(low[v(i)]>=dfn[x])
		{
			flag++;
			if(x!=root||flag>1)iscut[x]=1;
			cnt++;int z;
			do{dcc[cnt].push_back(z=stack[top--]);}while(z!=v(i));
			dcc[cnt].push_back(x);
		}
	}
	else low[x]=min(low[x],dfn[v(i)]);
}
int new_id[MAXN],c[MAXN];
int f[MAXN][20],dep[MAXN];
void dfs(int x,int fa,int deep)
{
	f[x][0]=fa;dep[x]=deep;
	for(int i=f2(x);i;i=n2(i))
	if(v2(i)!=fa)
		dfs(v2(i),x,deep+1);
}
int ans[MAXN],eans[MAXN];
void dfs2(int x,int fa)
{
	for(int i=f2(x);i;i=n2(i))
	if(v2(i)!=fa)
	{
		dfs2(v2(i),x);
		eans[x]+=eans[v2(i)];
	}
}
int LCA(int x,int y)
{
	if(dep[x]>dep[y])swap(x,y);
	while(dep[x]!=dep[y])
		for(int i=0;;i++)
		if(dep[f[y][i]]<dep[x])
		{y=f[y][i-1];break;}
	if(x==y)return x;
	while(f[x][0]!=f[y][0])
		for(int i=0;;i++)
		if(f[x][i]==f[y][i])
		{x=f[x][i-1],y=f[y][i-1];break;}
	return f[x][0];
}
inline void add(int u,int v);
inline void add2(int u,int v);
signed main()
{
//	freopen("in.txt","r",stdin);

	scanf("%d%d%d",&n,&m,&q);
	int a,b;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&a,&b);
		add(a,b),add(b,a);
	}
	for(int i=1;i<=n;i++)
	if(!dfn[i]){root=i;tarjan(i);}
	num=cnt;
	for(int i=1;i<=n;i++)
	if(iscut[i])new_id[i]=++num;
	for(int i=1;i<=cnt;i++)
		for(int j=0;j<dcc[i].size();j++)
		{
			int x=dcc[i][j];
			if(iscut[x])
				 add2(i,new_id[x]),add2(new_id[x],i);
			else c[dcc[i][j]]=i;
		}
	dfs(1,0,1);
	for(int j=1;j<20;j++)
		for(int i=1;i<=num;i++)
		f[i][j]=f[f[i][j-1]][j-1];
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&a,&b);
		if(!iscut[a])ans[a]++;
		if(!iscut[b])ans[b]++;
		int ca=iscut[a]?new_id[a]:c[a],
			cb=iscut[b]?new_id[b]:c[b],
			lca=LCA(ca,cb);
		eans[ca]++,eans[cb]++;
		eans[f[lca][0]]--,eans[lca]--;
	}
	dfs2(1,0);
	for(int i=1;i<=n;i++)
		printf("%d
",iscut[i]?eans[new_id[i]]:ans[i]);
}
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;
}
inline void add2(int u,int v)
{
	++num_e2;
	u2(num_e2)=u;
	v2(num_e2)=v;
	n2(num_e2)=f2(u);
	f2(u)=num_e2;
}
原文地址:https://www.cnblogs.com/Al-Ca/p/11182011.html