BZOJ3331 [BeiJing2013]压力 广义圆方树

3331: [BeiJing2013]压力

Description

如今,路由器和交换机构建起了互联网的骨架。处在互联网的骨干位置的核心路由器典型的要处理100Gbit/s的网络流量。他们每天都生活在巨大的压力之下。

小强建立了一个模型。这世界上有N个网络设备,他们之间有M个双向的链接。这个世界是连通的。在一段时间里,有Q个数据包要从一个网络设备发送到另一个网络设备。

一个网络设备承受的压力有多大呢?很显然,这取决于Q个数据包各自走的路径。不过,某些数据包无论走什么路径都不可避免的要通过某些网络设备。

你要计算:对每个网络设备,必须通过(包括起点、终点)他的数据包有多少个?

Input

第一行包含3个由空格隔开的正整数N,M,Q。

接下来M行,每行两个整数u,v,表示第u个网络设备(从1开始编号)和

第v个网络设备之间有一个链接。u不会等于v。两个网络设备之间可能有多个链接。

接下来Q行,每行两个整数p,q,表示第p个网络设备向第q个网络设备发送了一个数据包。p不会等于q。

Output

输出N行,每行1个整数,表示必须通过某个网络设备的数据包的数量。

Sample Input

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

Sample Output

2
1
1
2

HINT

 

【样例解释】

设备1、2、3之间两两有链接,4只和1有链接。4想向2和3各发送一个数据包。显然,这两个数据包必须要经过它的起点、终点和1。

【数据规模和约定】

对于40%的数据,N,M,Q≤2000

对于60%的数据,N,M,Q≤40000

对于100%的数据,N≤100000,M,Q≤200000

 

 

 

 

 

题解

先讲一下圆方树

首先要知道有一种图叫仙人掌

仙人掌就是一个没有共边环的连通图

如图:

这样就不是仙人掌(因为有共边环):

这样也不是(因为不连通):

我们定义原图中的每个点是圆点

对于每个环,我们可以新建一个方点,然后把原来环上的边删掉,把该环上所以的点连向这个方点:

圆方树就构好啦

 

广义圆方树就是对于任意图,我们对于每一个点双新建一个方点,然后点双中所有点向方点连边

其实建广义圆方树和建圆方树的代码是一样的

 

然后我们来看上面的题目

就会发现它是一道广义圆方树的板题

直接把广义圆方树建出来,然后树上差分一下就好啦

树剖一下就A了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 200005
#define M 400005
int fir[N],nxt[2*N],to[2*N],cnt;
void adde(int a,int b)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
	to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int dfn[N],low[N],stk[N],tp,dc,pbccnt;
vector<int> pbc[N];
void dfs(int u,int fa)
{
	dfn[u]=low[u]=++dc;
	stk[tp++]=u;
	int v,p;
	for(p=fir[u];p;p=nxt[p]){
		v=to[p];
		if(!dfn[v]){
			dfs(v,u);low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				pbccnt++;
				while(tp>0){
					pbc[pbccnt].push_back(stk[--tp]);
					if(stk[tp]==v)
						break;
				}
				pbc[pbccnt].push_back(u);
			}
		}
		else if(v!=fa) low[u]=min(low[u],dfn[v]);
	}
}
int fa[N],dep[N],son[N],siz[N],top[N];
void dfs1(int u)
{
	dep[u]=dep[fa[u]]+1;
	int v,p;siz[u]=1;
	for(p=fir[u];p;p=nxt[p]){
		v=to[p];
		if(v!=fa[u]){
			fa[v]=u;dfs1(v);siz[u]+=siz[v];
			if(siz[son[u]]<siz[v])
				son[u]=v;
		}
	}
}
void dfs2(int u)
{
	if(son[u]) top[son[u]]=top[u],dfs2(son[u]);
	int v,p;
	for(p=fir[u];p;p=nxt[p]){
		v=to[p];
		if(v!=son[u]&&v!=fa[u])
			top[v]=v,dfs2(v);
	}
}
int LCA(int x,int y)
{
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}
int sum[N];
void solve(int u)
{
	int v,p;
	for(p=fir[u];p;p=nxt[p]){
		v=to[p];
		if(v!=fa[u]){
			solve(v);
			sum[u]+=sum[v];
		}
	}
}
int main()
{
	int n,m,Q,i,j,k,u,v;
	n=gi();m=gi();Q=gi();
	for(i=1;i<=m;i++){
		u=gi();v=gi();
		adde(u,v);
	}
	for(i=1;i<=n;i++)
		if(!dfn[i]) dfs(i,0);
	memset(fir,0,sizeof(fir));cnt=0;
	for(i=1;i<=pbccnt;i++)
		for(j=0,k=pbc[i].size();j<k;j++)
			adde(n+i,pbc[i][j]);
	dfs1(1);top[1]=1;dfs2(1);
	for(i=1;i<=Q;i++){
		u=gi();v=gi();
		sum[u]++;sum[v]++;
		int lca=LCA(u,v);
		sum[fa[lca]]--;sum[lca]--;
	}
	solve(1);
	for(i=1;i<=n;i++)
		printf("%d\n",sum[i]);
}

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值