2019.03.07【APIO2018】【洛谷P4630】【BZOJ5463】铁人两项(圆方树)(树形DP)

洛谷传送门

BZOJ传送门


解析:

对所有点双建立圆方树,设圆点权值为 − 1 -1 1,方点权值为点双大小。那么原题转化为求树上所有圆点两两路径的权值和,直接上树形DP。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

cs int N=4e5+5;
int n,tot,m;
struct Graph{
	int to[N],nxt[N],last[N],ecnt;
	void addedge(int u,int v){
		nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
	}
}g1,g2;

int dfn[N],low[N],dfs_clock;
int sta[N],top;
int val[N],siz[N],sum;

void tarjan(int u){
	dfn[u]=low[u]=++dfs_clock;
	sta[++top]=u;
	siz[u]=1;val[u]=-1;
	for(int re e=g1.last[u],v=g1.to[e];e;v=g1.to[e=g1.nxt[e]]){
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				g2.addedge(u,++tot);
				val[tot]=1;
				int x;
				do{
					x=sta[top--];
					g2.addedge(tot,x);
					siz[tot]+=siz[x];
					++val[tot];
				}while(x!=v);
				siz[u]+=siz[tot];
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
}

ll ans;
void dfs(int u){
	if(u<=n)ans+=(ll)(sum-1)*val[u];
	ans+=(ll)(sum-siz[u])*siz[u]*val[u];
	for(int re e=g2.last[u],v=g2.to[e];e;v=g2.to[e=g2.nxt[e]]){
		ans+=(ll)(sum-siz[v])*siz[v]*val[u];
		dfs(v);
	}
}

signed main(){
	tot=n=getint(),m=getint();
	for(int re i=1;i<=m;++i){
		int u=getint(),v=getint();
		g1.addedge(u,v);
		g1.addedge(v,u);
	}
	for(int re i=1;i<=n;++i)if(!dfn[i])tarjan(i),sum=siz[i],dfs(i);
	cout<<ans;
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值