【BZOJ3331】[BeiJing2013]压力 Tarjan求点双

【BZOJ3331】[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

题解:显然先用Tarjan求缩块。。。怎么求呢。。。基本功不扎实又去学了一发。

最后我们会得到一个树形结构,但是。。。怎么得到呢。。。其实对于每个块新建一个点连向块中的所有点即可。

然后就是一个类似于树的东西了,怎么统计树上有哪些路径必经一个点呢?差分即可。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=200010;
int n,m,q,top,tot,sum,cnt;
int sta[maxn],low[maxn],HEAD[maxn],NEXT[maxn<<1],TO[maxn<<1],head[maxn<<1],next[maxn<<2],to[maxn<<2];
int s[maxn<<1],fa[19][maxn<<1],Log[maxn<<1],dep[maxn<<1],Q[maxn<<1];
inline void ADD(int a,int b)
{
	TO[cnt]=b,NEXT[cnt]=HEAD[a],HEAD[a]=cnt++;
}
inline void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void tarjan(int x)
{
	dep[x]=low[x]=++tot,sta[++top]=x;
	for(int y,i=HEAD[x],t;i!=-1;i=NEXT[i])
	{
		y=TO[i];
		if(!dep[y])
		{
			tarjan(y),low[x]=min(low[x],low[y]);
			if(low[y]>=dep[x])
			{
				sum++;
				do
				{
					t=sta[top--],add(sum,t),add(t,sum);
				}while(t!=y);
				add(sum,x),add(x,sum);
			}
		}
		else	low[x]=min(low[x],dep[y]);
	}
}
void dfs(int x)
{
	Q[++Q[0]]=x;
	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=fa[0][x])	fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
}
inline int lca(int a,int b)
{
	int i;
	if(dep[a]<dep[b])	swap(a,b);
	for(i=Log[dep[a]-dep[b]];i>=0;i--)	if(dep[fa[i][a]]>=dep[b])	a=fa[i][a];
	if(a==b)	return a;
	for(i=Log[dep[a]];i>=0;i--)	if(fa[i][a]!=fa[i][b])	a=fa[i][a],b=fa[i][b];
	return fa[0][a];
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
int main()
{
	//freopen("bz3331.in","r",stdin);
	n=rd(),m=rd(),q=rd(),sum=n;
	memset(head,-1,sizeof(head)),memset(HEAD,-1,sizeof(HEAD));
	int i,j,a,b,c;
	for(i=1;i<=m;i++)	a=rd(),b=rd(),ADD(a,b),ADD(b,a);
	cnt=0,tarjan(1),dep[1]=1,dfs(1);
	for(i=2;i<=sum;i++)	Log[i]=Log[i>>1]+1;
	for(j=1;(1<<j)<=sum;j++)	for(i=1;i<=sum;i++)	fa[j][i]=fa[j-1][fa[j-1][i]];
	for(i=1;i<=q;i++)
	{
		a=rd(),b=rd(),c=lca(a,b);
		s[a]++,s[b]++,s[c]--,s[fa[0][c]]--;
	}
	for(i=sum;i;i--)	a=Q[i],s[fa[0][a]]+=s[a];
	for(i=1;i<=n;i++)	printf("%d\n",s[i]);
	return 0;
}
时间: 2024-10-28 05:53:05

【BZOJ3331】[BeiJing2013]压力 Tarjan求点双的相关文章

[bzoj3331] [BeiJing2013] 压力(tarjan 点双连通分量)

题干: 这世界上有N个网络设备,他们之间有M个双向的链接.这个世界是连通的.在一段时间里,有Q个数据包要从一个网络设备发送到另一个网络设备.一个网络设备承受的压力有多大呢?很显然,这取决于Q个数据包各自走的路径.不过,某些数据包无论走什么路径都不可避免的要通过某些网络设备.你要计算:对每个网络设备,必须通过(包括起点.终点)他的数据包有多少个? 对于40%的数据,N,M,Q≤2000 对于60%的数据,N,M,Q≤40000 对于100%的数据,N≤100000,M,Q≤200000 题解: 必

bzoj1123 BLO tarjan求点双连通分量

填坑--链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1123 题意:问切断第i个点之后多少对点不再联通. 就是个求割点同时计算出双连通分量大小嘛-- 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=10000

BZOJ3331: [BeiJing2013]压力

传送门 Tarjan的三大应用之一:求解点双联通分量. 求解点双联通分量.然后缩点,差分优化即可. //BZOJ 3331 //by Cydiater //2016.10.29 #include <iostream> #include <cmath> #include <cstdlib> #include <cstdio> #include <queue> #include <map> #include <cstring>

【POJ3352】Road Construction tarjan求边-双连通分量,裸题模板题

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42671851 其实我就是觉得原创的访问量比未授权盗版多有点不爽233... 裸题只给模板. tarjan可以实现. 太水不发题解. 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 1010 #define M 202

【POJ1523】SPF tarjan求点-双连通分量 裸题模板题

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42671865 其实我就是觉得原创的访问量比未授权盗版多有点不爽233... 题意:求哪些点是割点,割掉以后能把图分成几块. 太水不欲发题解. tarjan就好,不懂看代码. 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define

Tarjan求点双连通分量

概述 在一个无向图中,若任意两点间至少存在两条"点不重复"的路径,则说这个图是点双连通的(简称双连通,biconnected) 在一个无向图中,点双连通的极大子图称为点双连通分量(简称双连通分量,Biconnected Component,BCC) 性质 任意两点间至少存在两条点不重复的路径等价于图中删去任意一个点都不会改变图的连通性,即BCC中无割点 若BCC间有公共点,则公共点为原图的割点 无向连通图中割点一定属于至少两个BCC,非割点只属于一个BCC 算法 在Tarjan过程中维

连通分量模板:tarjan: 求割点 &amp;&amp; 桥 &amp;&amp; 缩点 &amp;&amp; 强连通分量 &amp;&amp; 双连通分量 &amp;&amp; LCA(最近公共祖先)

PS:摘自一不知名的来自大神. 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最

tarjan算法求桥双连通分量 POJ 3177 Redundant Paths

POJ 3177 Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12598   Accepted: 5330 Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the re

hdoj 2242 考研路茫茫——空调教室 【无向图求边双联通 缩点 + 树形dp】

考研路茫茫--空调教室 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2447    Accepted Submission(s): 721 Problem Description 众所周知,HDU的考研教室是没有空调的,于是就苦了不少不去图书馆的考研仔们.Lele也是其中一个.而某教室旁边又摆着两个未装上的空调,更是引起人们无限YY