bzoj3331: [BeiJing2013]压力

如今,路由器和交换机构建起了互联网的骨架。处在互联网的骨干位置的核心路由器典型的要处理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?'\n':' ');
	return 0;
}

  

posted @ 2016-12-09 13:13  CHADLZX  阅读(494)  评论(0编辑  收藏  举报