圆方树

圆方树是将图转化成树的一种工具。

在图中找到每一个点双联通分量,用圆点表示原图的点,方点表示每一个点双连通分量,然后将每个圆点和它对应的方点连边,就形成了圆方树。

圆方树的详细介绍

P4630铁人两项

点双有一个很好的性质:对于一个点双中的两个点,它们的所有简单路径的并集,恰好完全等于这个点双。

因此,两点在原图中的路径集合,就是两点在圆方树中的路径经过的方点的相邻圆点的集合。

因此,当起点和终点固定时,中转点数量等于起点与终点路径并集的点的数量2(除去起点和终点本身)

如何求点的数量?这需要一个圆方树的常用技巧:路径统计时,点赋上合适的权值。
本题中,每个方点的权值为对应点双的大小,而每个圆点权值为 1。这样赋权后则有两圆点间圆方树上路径点权和,恰好等于原图中简单路径并集大小 2

因此,问题转化为统计圆方树上 两圆点路径权值和。

暴力求是O(n2)的,因此考虑贡献法。统计每一个点对答案的贡献,也就是它的权值乘以经过它的路径条数。通过树形DP求即可。

code:

#include<iostream>
#include<cstdio>
#include<vector>
#define int long long
using namespace std;
const int l=4e5+5;
int n,m,u,v,root,num,tim,tot,cnt,ans,r,siz[l],vis[l],w[l],stk[l],dfn[l],low[l],nxt[l],head[l],ver[l];
bool cut[l];vector <int> p[l];
void add(int x,int y){
	nxt[++tot]=head[x];head[x]=tot;ver[tot]=y;
}
void tarjan(int x){
	dfn[x]=low[x]=++tim;
    ++num;
	stk[++r]=x;
	if(x==root&&head[x]==0){
		++cnt;w[cnt]=1;
        p[cnt].push_back(x);
        p[x].push_back(cnt);
		return ;
	}
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(!dfn[y]){
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x]){
				++cnt;w[cnt]=0;
				int z;
				do{
					z=stk[r--];
					p[cnt].push_back(z);
                    p[z].push_back(cnt);
                    ++w[cnt];
				}while(z!=y);
                ++w[cnt];
				p[cnt].push_back(x);
                p[x].push_back(cnt);
			}
		}
		else
			low[x]=min(low[x],dfn[y]);
	}
}
void dfs(int x,int fa){
    vis[x]=1;
    siz[x]=(x<=n);
    for(int i=0;i<p[x].size();++i){
        if(p[x][i]!=fa){
            dfs(p[x][i],x);
            ans+=2ll*w[x]*siz[x]*siz[p[x][i]];
            siz[x]+=siz[p[x][i]];
        }
    }
    ans+=2ll*w[x]*siz[x]*(num-siz[x]);
}
signed main(){
	scanf("%lld%lld",&n,&m);
    cnt=n;
    for(int i=1;i<=n;++i)
        w[i]=-1;
	for(int i=1;i<=m;++i){
		scanf("%lld%lld",&u,&v);
		if(u!=v)
			add(u,v),add(v,u);
	}
	for(int i=1;i<=n;++i)
		if(!dfn[i])
			num=0,root=i,tarjan(i),dfs(i,0);
    printf("%lld\n",ans);
	return 0;
}
posted @   andy_lz  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示