Jzoj4784 Map

这个题意很简单,就是问你连一条边会增加多少双联通点对

按照一般的方法,先用Tarjan缩点化为一颗树,每次连起来就在树上找路径统计答案

答案的统计方法,设树上节点i(原图的一个双联通块)的大小为v[i]

那么一条路径[x,y]的端点被连接起来,贡献应该是(Σv[i])^2-Σv[i]^2,其中i∈x~y的路径

这样的话可以用倍增或者树剖求lca来解决

码量比较大

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 200010
#define LL long long
using namespace std;
struct Edge{ int u,v,nt; } G[N<<3];
int c=1,q,h[N],dfn[N],clk=0,Col=0;
int n,m,low[N],col[N],du[N]; bool b[N<<1];
inline void adj(int x,int y){
	G[++c]=(Edge){x,y,h[x]}; h[x]=c;
	G[++c]=(Edge){y,x,h[y]}; h[y]=c;
}
void tarjan(int u,int v){
	clk++; low[v]=dfn[v]=clk;
	for(int w,i=h[v];i;i=G[i].nt)
		if((i&~1)!=(u&~1)){
			if(!dfn[w=G[i].v]){
				tarjan(i,w);
				if(low[w]==dfn[w] || low[w]>dfn[v]){ b[i]=1; b[i^1]=1; }
				else low[v]=min(low[v],low[w]);
			} else low[v]=min(low[v],dfn[w]);
		}
}
void dfs(int x,int u,int Cl){
	col[x]=Cl; du[Cl]++;
	for(int v,i=h[x];i;i=G[i].nt)
		if((v=G[i].v)!=u&&!b[i]&&!col[v]) dfs(v,x,Cl);
}
struct Tree{
	Edge G[N<<1]; int h[N],d[N],f[18][N],cnt; LL s1[N],s2[N];
	//Tree(){ cnt=0; }
	inline void adj(int x,int y){ 
		G[++cnt]=(Edge){x,y,h[x]}; h[x]=cnt; 
		G[++cnt]=(Edge){y,x,h[y]}; h[y]=cnt; 
	}
	void dfs(int x,int p){
		d[x]=d[p]+1; f[0][x]=p;
		s1[x]=s1[p]+du[x]; s2[x]=s2[p]+(LL)du[x]*du[x];
		for(int j=1;j<18;++j)
			f[j][x]=f[j-1][f[j-1][x]];
		for(int v,i=h[x];i;i=G[i].nt)
			if((v=G[i].v)!=p) dfs(v,x);
	}
	void build(){ dfs(1,0); }
	void swim(int& x,int d){
		for(int i=0;d;++i,d>>=1) if(d&1) x=f[i][x]; 
	}
	int gLca(int x,int y){
		if(d[x]>d[y]) swap(x,y);
		LL x1=0,x2=0;
		swim(y,d[y]-d[x]);
		if(x==y) return x;
		for(int j=17;;){
			for(;~j&&f[j][x]==f[j][y];--j);
			if(j<0) return f[0][x];
			x=f[j][x]; y=f[j][y];
		}
	}
	LL query(int x,int y){
		int p=gLca(x,y);
		LL x1=s1[x]+s1[y]-2*s1[p]+du[p];
		LL x2=s2[x]+s2[y]-2*s2[p]+(LL)du[p]*du[p]; 
		return x1*x1-x2;
	}
} T;
int main(){	
	scanf("%d%d%d",&n,&m,&q);
	for(int x,y,i=0;i<m;++i){
		scanf("%d%d",&x,&y);
		adj(x,y);
	}
	tarjan(0,1); T.cnt=0;
	for(int i=1;i<=n;++i) 
		if(!col[i]) dfs(i,0,++Col);
	for(int i=2;i<=c;i+=2) 
		if(col[G[i].u]!=col[G[i].v]) T.adj(col[G[i].u],col[G[i].v]);
	T.build(); LL SS=0;
	for(int x,y;q--;SS+=T.query(col[x],col[y])) scanf("%d%d",&x,&y);
	for(printf("%lld\n",SS);;) return 0;
}

posted @ 2017-10-25 19:01  扩展的灰(Extended_Ash)  阅读(113)  评论(0编辑  收藏  举报