如今,路由器和交换机构建起了互联网的骨架。处在互联网的骨干位置的核心路由器典型的要处理100Gbit/s的网络流量。他们每天都生活在巨大的压力之下。
小强建立了一个模型。这世界上有N个网络设备,他们之间有M个双向的链接。这个世界是连通的。在一段时间里,有Q个数据包要从一个网络设备发送到另一个网络设备。
一个网络设备承受的压力有多大呢?很显然,这取决于Q个数据包各自走的路径。不过,某些数据包无论走什么路径都不可避免的要通过某些网络设备。
你要计算:对每个网络设备,必须通过(包括起点、终点)他的数据包有多少个?
题解:比较裸的双联通分量题目;
首先tarjan求双连通分量,将原图变成一棵树,那么题目要求的就是每个点被多少路径经过,求lca,然后做一个树上差分,判断一下这个点是否是原图的割点,若是,加上经过这一点的路径数;
不要忘了特判一下每个点起点和终点;
树链剖分求lca应该更快;
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
#include<iomanip>
#include<stack>
using namespace std;
#define FILE "dealing"
#define up(i,j,n) for(int i=(j);i<=(n);i++)
#define pii pair<int,int>
#define LL int
#define mem(f,g) memset(f,g,sizeof(f))
namespace IO{
char buf[1<<15],*fs,*ft;
int gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?-1:*fs++;}
int read(){
int ch=gc(),f=0,x=0;
while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
return f?-x:x;
}
int readint(){
int ch=getchar(),f=0,x=0;
while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?-x:x;
}
}using namespace IO;
const int maxn=201000,inf=100000000;
int n,m,Q;
struct node{
int y,next;
}e[maxn],E[maxn];
int linkk[maxn],len=0,linker[maxn],Len=0;
inline void insert(int x,int y,int* linkk,int &len,node* e){e[++len].y=y;e[len].next=linkk[x];linkk[x]=len;}
int x,y,ans[maxn],N=0,last=0,id[maxn],re[maxn];//记录每个点在新图中的编号;
int u[maxn],v[maxn];
namespace maketree{
vector<int> bcc[maxn];
int pre[maxn],low[maxn],iscut[maxn],b[maxn],dfs_clock=0,cnt=0;
int u[maxn],v[maxn],top=0;
void tarjan(int x,int fa){
pre[x]=low[x]=++dfs_clock;int child=0;
for(int i=linkk[x];i;i=e[i].next){
if(e[i].y==fa)continue;
if(!pre[e[i].y]){
u[++top]=x,v[top]=e[i].y;
tarjan(e[i].y,x);
if(low[e[i].y]<low[x])low[x]=low[e[i].y];
if(low[e[i].y]>=pre[x]){
iscut[x]=1;cnt++;bcc[cnt].clear();
while(true){
if(b[u[top]]!=cnt){bcc[cnt].push_back(u[top]);b[u[top]]=cnt;}
if(b[v[top]]!=cnt){bcc[cnt].push_back(v[top]);b[v[top]]=cnt;}
if(u[top]==x&&v[top]==e[i].y){top--;break;}
top--;
}
}
}
else if(pre[e[i].y]<pre[x]){
u[++top]=x,v[top]=e[i].y;
if(pre[e[i].y]<low[x])low[x]=pre[e[i].y];
}
}
if(!fa&&child==1)iscut[x]=0;
}
void slove(){
tarjan(1,0);
last=N=cnt;
int x;
up(i,1,cnt){
for(int j=0;j<bcc[i].size();j++){
x=bcc[i][j];
if(iscut[x]){
if(!id[x])id[x]=++N,re[id[x]]=x;//缩点后的点对应的实际的点
insert(id[x],i,linker,Len,E);
insert(i,id[x],linker,Len,E);
}
else id[x]=i;
}
}
}
};
int num[maxn];
namespace st{
int fa[maxn][31],dep[maxn];
void dfs(int x,int f){
for(int i=linker[x];i;i=E[i].next){
if(E[i].y==f)continue;
fa[E[i].y][0]=x;
dep[E[i].y]=dep[x]+1;
dfs(E[i].y,x);
}
}
void getlca(int x,int y){
if(dep[y]<dep[x])swap(x,y);
int u=x,v=y;
for(int i=30;i>=0;i--)
if(dep[y]-dep[x]>=(1<<i))y=fa[y][i];
if(x==y){
num[fa[x][0]]-=1;
num[v]+=1;
return;
}
for(int i=30;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
num[fa[fa[x][0]][0]]-=1;
num[fa[x][0]]-=1;
num[u]+=1;num[v]+=1;
}
void slove(){
dfs(1,0);
up(j,1,30)up(i,1,N)fa[i][j]=fa[fa[i][j-1]][j-1];
int x,y;
up(i,1,Q){
u[i]=x=read(),v[i]=y=read();
x=id[x];y=id[y];
if(x!=y)getlca(x,y);
}
}
};
int dfs(int x,int fa){
int sum=num[x];
for(int i=linker[x];i;i=E[i].next){
if(E[i].y==fa)continue;
sum+=dfs(E[i].y,x);
}
if(x>last){
ans[re[x]]+=sum;
}
return sum;
}
int main(){
n=read(),m=read(),Q=read();
up(i,1,m){
x=read(),y=read();
insert(x,y,linkk,len,e);
insert(y,x,linkk,len,e);
}
maketree::slove();
st::slove();
up(i,1,Q){
if(id[u[i]]<=last)ans[u[i]]++;
if(id[v[i]]<=last)ans[v[i]]++;
}
dfs(1,0);
up(i,1,n)printf("%d%c",ans[i],i==n?'
':' ');
return 0;
}