如今,路由器和交换机构建起了互联网的骨架。处在互联网的骨干位置的核心路由器典型的要处理100Gbit/s的网络流量。他们每天都生活在巨大的压力之下。
小强建立了一个模型。这世界上有N个网络设备,他们之间有M个双向的链接。这个世界是连通的。在一段时间里,有Q个数据包要从一个网络设备发送到另一个网络设备。
一个网络设备承受的压力有多大呢?很显然,这取决于Q个数据包各自走的路径。不过,某些数据包无论走什么路径都不可避免的要通过某些网络设备。
你要计算:对每个网络设备,必须通过(包括起点、终点)他的数据包有多少个?
第一行包含3个由空格隔开的正整数N,M,Q。
接下来M行,每行两个整数u,v,表示第u个网络设备(从1开始编号)和第v个网络设备之间有一个链接。u不会等于v。两个网络设备之间可能有多个链接。
接下来Q行,每行两个整数p,q,表示第p个网络设备向第q个网络设备发送了一个数据包。p不会等于q。
输出N行,每行1个整数,表示必须通过某个网络设备的数据包的数量。
Sample Input4 4 2
1 2
1 3
2 3
1 4
4 2
4 3
2
1
1
2
设备1、2、3之间两两有链接,4只和1有链接。4想向2和3各发送一个数据包。显然,这两个数据包必须要经过它的起点、终点和1。
Data Constraint对于40%的数据,N,M,Q≤2000
对于60%的数据,N,M,Q≤40000
对于100%的数据,N≤100000,M,Q≤200000
注意,邻接表要从1开始编号!!!(改了我一个晚上)
首先,按 DFS 序遍历原图,构造出一棵 DFS 树。那么对于一对节点 u,v,删除后改变
它们连通性的点只有两种:
1,节点 u 或节点 v。
2,在 u 到 v 的 DFS 树路径上,且删除后 u,v 的连通性改变。
其中第一类节点统计很简单,关键是第二类节点。我们可以把利用前面的 DFS 树对原图求一次双连通分量,然后把问题转化成求每个节点被路径覆盖几次。这个可以用 LCA+树形DP在 O(N)的时间内解决。当然要注意减去和第一类节点重复的部分。时间复杂度为O(nlogn)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=300077;
int list[maxn*2],Fa[maxn][23],dfn[maxn],low[maxn],s[maxn],Ans[maxn],dep[maxn];
int n,m,q,Cnt=0,cnt=0,CNT=0,t=0,tot=0;
struct E
{
int to,next;
}e[maxn*2];
struct A
{
int x,y;
}a[maxn*2];
void add(int u,int v)
{
e[++cnt].to=v; e[cnt].next=list[u]; list[u]=cnt;
}
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++t; s[++tot]=x;
for(int i=list[x]; i; i=e[i].next)
{
if((fa^1)==i) continue;
int y=e[i].to;
if(!dfn[y])
{
tarjan(y,i);
if(dfn[x]==low[y])
{
Cnt++;
for(; s[tot]!=y; tot--) a[++CNT].x=s[tot],a[CNT].y=Cnt+n;
a[++CNT].x=y,a[CNT].y=Cnt+n;
a[++CNT].x=x,a[CNT].y=Cnt+n;
tot--;
}
if (low[y]==dfn[y]) a[++CNT].x=x, a[CNT].y=y;
low[x]=min(low[x],low[y]);
}else low[x]=min(low[x],dfn[y]);
}
if (low[x]==dfn[x]) tot--;
}
void build(int x,int fa)
{
dep[x]=dep[fa]+1,Fa[x][0]=fa;
for(int i=1; i<=20; i++) Fa[x][i]=Fa[Fa[x][i-1]][i-1];
for(int i=list[x]; i; i=e[i].next) if(e[i].to!=fa) build(e[i].to,x);
}
int Lca(int u, int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int i=20; i+1; i--)
if(dep[Fa[u][i]]>=dep[v]) u=Fa[u][i];
if(u==v) return u;
for(int i=20; i+1; i--)
if(Fa[u][i]!=Fa[v][i]) u=Fa[u][i],v=Fa[v][i];
return Fa[u][0];
}
void Solve(int x)
{
for(int i=list[x]; i; i=e[i].next)
{
int y=e[i].to;
if (y==Fa[x][0]) continue;
Solve(y);
Ans[x]+=Ans[y];
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
cnt=1;
for(int i=1; i<=m; i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
t=0; tarjan(1,0);
memset(e,0,sizeof(e));
memset(list,0,sizeof(list));
for(int i=1; i<=CNT; i++) add(a[i].x,a[i].y),add(a[i].y,a[i].x);
build(1,0);
for (int i=1; i<=q; i++)
{
int u,v;
scanf("%d%d",&u,&v);
int lca=Lca(u,v);
Ans[u]++; Ans[v]++; Ans[lca]--; Ans[Fa[lca][0]]--;
}
Solve(1);
for (int i=1; i<=n; i++) printf("%d\n",Ans[i]);
}