写挂,求助。
查看原帖
写挂,求助。
697299
hamster000楼主2024/2/23 16:14

我的做法是,考虑建立圆方树,方点的权值是点双的大小,圆点的权值是-1,计算每个节点的带权深度,然后枚举LCA求解。

#include <bits/stdc++.h>
using namespace std;
int n,m;
struct edge{
	int to,e;
};
const int maxn=1e6+10;
int w[maxn],sum[maxn];
vector<edge> vec[maxn];
int cnt,dfn[maxn],low[maxn];
vector<int> tree[maxn];
int tot=0;
stack <int> s;
void tarjan(int k,int e){
	low[k]=dfn[k]=++cnt;
	s.push(k);
	int son=0;
	for(auto to:vec[k]){
		int t=to.to,num=to.e;
		if(e==(num^1)) continue;
		if(!dfn[t]){
			son++;
			tarjan(t,num),low[k]=min(low[k],low[t]);
			if(low[t]>=dfn[k]){
				tot++;
				tree[k].push_back(tot);
				tree[tot].push_back(k);
				w[k]=-1;
				w[tot]++;
				while(s.top()!=t){
					w[tot]++;
					w[s.top()]=-1;
					tree[s.top()].push_back(tot);
					tree[tot].push_back(s.top());
					s.pop();
				}
				w[s.top()]=-1;
				tree[s.top()].push_back(tot);
				tree[tot].push_back(s.top());
				s.pop();
			}
		} 
		else low[k]=min(low[k],dfn[t]);
	}
}
//考虑lca(a,b),只有两个儿子的情况,s在左f在右,s可以是左边的所有节点,f是右边的所有节点
//dis a,b=dep[a]+dep[b]-dep[lca(a,b)] -dep[fa[lca(a,b)]]
//sum(dis(a,b)) a,b
//=sum(dep[a]+dep[b]-dep[t]-dep[fa[t]]);
//
//对于多个儿子的情况,合并每个儿子即可。
int siz[maxn],top[maxn],fa[maxn],son[maxn],dep[maxn];
long long depsum[maxn];
void dfs1(int x,int f){
	siz[x]=1;fa[x]=f;dep[x]=dep[f]+w[x];
	depsum[x]=dep[x];
	for(auto to:tree[x]){
		if(to==f) continue;
		dfs1(to,x);
		siz[x]+=siz[to];
		if(siz[to]>siz[son[x]]) son[x]=to;
		depsum[x]+=depsum[to];
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin >> n >> m;
	tot=n;
	for(int i=1;i<=m;i++){
		int u,v;
		cin >> u >> v;
		vec[u].push_back({v,2*i});
		vec[v].push_back({u,2*i+1});
	}
	for(int i=1;i<=tot;i++){
		if(!dfn[i]){
			tarjan(i,0);
			dfs1(i,0);
		}
	}
	
	long long ans=0;
    for(int i=1;i<=tot;i++){
		vector<int> v;
		for(auto to:tree[i]){
			if(to!=fa[i]){
				v.push_back(to);
			}
			
		}
		int siza=0,sizb=0,sumdepa=0,sumdepb=0;
		if(v.size()==1) {
			ans+=depsum[v[0]];
			continue;
		}
		if(!v.size()){
			ans+=dep[i];
			continue ;
		}
		for(int j=0;j<v.size()-1;j++){//怀疑这里统计答案出错,求助。
			if(j==0){
				siza=siz[v[j]];
				sumdepa=depsum[j];
			}
			sizb=siz[v[j+1]];
			sumdepb=depsum[j+1];
			ans+=siza*sumdepb+sizb*sumdepa-siza*sizb*(dep[i]+dep[fa[i]]);
			sumdepa+=sumdepb;
			siza+=sizb;
	    }
	}
	
	cout << ans << endl;
}

2024/2/23 16:14
加载中...