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

【样例解释】

设备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]);
}