Tarjan+LCA POJ 3694 Network

链接: http://poj.org/problem?id=3694

给定一无向图,保证是连通的, 之后 逐渐加边,求每次加边后的,图的桥的数目。 由于 数据比较大,要用到LCA + 缩点。

值得学习的 也是 这两点, 求树种两点的 最短路径数,也是这么求。

先Tarjan一下, 求得割边,同时 缩点, 成为一棵树, 树上的边都是 桥,之后添边,两点 有同一个 parent 则 不减少桥的数量, 否则,通过LCA 减掉两点间的路径(且是桥)数目。

code    :

#include
#include
#include
#include
using namespace std;
#define INF 1000000000
#define N 100005
#define M 200005
int low[N],dfn[N],vis[N],tot,hh[N],n,m,q,ad,par[N],tot2,hh2[N],sum,lev[N],pre[N],vv[N];
struct node
{
	int u,v,next,ge;//tag use?
}edge[2*M],edge2[2*M];
void init()
{
	memset(hh,-1,sizeof(hh)); tot=0;
	memset(vis,0,sizeof(vis));
	ad=0; sum=0;
	for(int i=1;i<=n;i++) par[i]=i;
}
void add2(int u,int v)
{
	edge2[tot2].u=u; edge2[tot2].v=v;
	edge2[tot2].next=hh2[u]; edge[tot2].ge=0;
	hh2[u]=tot2++;
}
void add(int u,int v)
{
	edge[tot].u=u; edge[tot].v=v;
	edge[tot].next=hh[u];edge[tot].ge=0;
	hh[u]=tot++;
}
int find(int x)
{
	if(x!=par[x]) par[x]=find(par[x]);
	return par[x];
}
void dfs(int u ,int p)
{
	dfn[u]=low[u]=++ad;
	vis[u]=1;
	for(int i=hh[u];i!=-1; i=edge[i].next)
	{
		int v=edge[i].v;
		if(!vis[v])
		{
			dfs(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>dfn[u])
			{
				sum++;
				edge[i].ge=1; edge[i^1].ge=1;
			}
			else
			{
				int x=find(u); int y=find(v);
				par[x]=y;
			}
		}
		else if(v!=p) low[u]=min(low[u],dfn[v]);
	}
}
void dfs_(int u,int p)
{
	lev[u]=p;
	for(int i=hh2[u];i!=-1;i=edge2[i].next)
	{
		int v=edge2[i].v;
		if(lev[v]>0) continue;
		pre[v]=u;
		vv[v]=1;//not have the most parent point .
		dfs_(v,p+1);
	}
}
void  lca(int x,int y)
{
	while(lev[x]>lev[y])
	{
		if(vv[x])
		{
			sum--; vv[x]=0;
		}
		x=pre[x];
	}
	while(lev[x]


你可能感兴趣的:(图论)