• 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
    ",SS);;) return 0;
    }

  • 相关阅读:
    CentOS7.9 安装 PG13 + repmgr +pgpool 实现负载均衡读写分离
    c# winForm中播放声音的三种方法
    C# 输入指定日期获取当前年的第一天 、当前年的最后一天
    微服务架构的优缺点,适合场景。
    Spring,SpringMVC,SpringBoot区别及联系
    cxgrid的使用模糊搜索
    pg中函数调用中的SQL语句
    oracle 查询备份
    oracle一次获取多表数据
    ToolTip
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477279.html
Copyright © 2020-2023  润新知