【bzoj3124】 Sdoi2013—直径

http://www.lydsy.com/JudgeOnline/problem.php?id=3124 (题目链接)

题意

  求树的直径以及直径的交。

Solution

  我的想法超麻烦,经供参考。。思路还是蛮简单的,就是细节实在是。。。写的我眼泪掉下来。

  首先直径很好求,2遍dfs,顺便求出点x儿子节点中的最长链f[x][0],次长链f[x][1]。

  考虑如何求直径的交。

  对于一条边(u,v),如果它是直径的交,当且仅当所有的直径都经过u,所有的直径都经过v,u的最长链+v的最长链+(u,v)=直径长度。

  所以考虑如何求出数组b[x],表示x节点是否被所有直径经过。大家可以自行脑补,我已经不知道自己是怎么AC的了。。

细节

  too much。

代码

// bzoj3124
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=200010;
struct edge {int to,next,w;}e[maxn<<1];
int head[maxn],son[maxn][2],sum[maxn][2],b[maxn],vis[maxn],cnt,n,tot,rt;
LL f[maxn][3],ans;

void link(int u,int v,int w) {
	e[++cnt]=(edge){v,head[u],w};head[u]=cnt;
	e[++cnt]=(edge){u,head[v],w};head[v]=cnt;
}
void dfs(int x,int fa,LL d) {
	if (ans<d) ans=d,rt=x;
	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) {
			dfs(e[i].to,x,d+e[i].w);
			if (f[x][0]<f[e[i].to][0]+e[i].w) {
				f[x][1]=f[x][0],f[x][0]=f[e[i].to][0]+e[i].w;
				son[x][1]=son[x][0],son[x][0]=e[i].to;
				sum[x][1]=sum[x][0],sum[x][0]=0;
			}
			else if (f[x][1]<f[e[i].to][0]+e[i].w) {
				son[x][1]=e[i].to;f[x][1]=f[e[i].to][0]+e[i].w;
				sum[x][1]=0;
			}
			if (f[x][0]==f[e[i].to][0]+e[i].w) sum[x][0]++;
			if (f[x][1]==f[e[i].to][0]+e[i].w) sum[x][1]++;
		}
}
bool Dfs(int x,int fa,LL d) {
	f[x][2]=d;
	int flag=1,val=b[x],count=0,p;
	if (f[x][0]+f[x][1]==ans) flag=0;
	val&=flag;
	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) {
			b[e[i].to]=b[x];
			if (e[i].to!=son[x][0] && e[i].to!=son[x][1]) b[e[i].to]=val;
			else {
				if (son[x][0]==e[i].to && sum[x][0]>2) b[e[i].to]=val;
				if (son[x][1]==e[i].to && sum[x][1]>1+(f[x][0]==f[x][1])) b[e[i].to]=val;
			}
			if (f[x][son[x][0]==e[i].to]+f[x][2]==ans) b[e[i].to]=0;
			int tmp=Dfs(e[i].to,x,max(f[x][son[x][0]==e[i].to],f[x][2])+e[i].w);
			if (!tmp) count++,p=e[i].to;
			b[x]&=tmp;flag&=tmp;
		}
	if (count>1)
		for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && b[e[i].to]) {
				b[e[i].to]=0;
				Dfs(e[i].to,x,max(f[x][son[x][0]==e[i].to],f[x][2])+e[i].w);
			}
	if (count==1)
		for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && b[e[i].to] && e[i].to!=p) {
				b[e[i].to]=0;
				Dfs(e[i].to,x,max(f[x][son[x][0]==e[i].to],f[x][2])+e[i].w);
			}
	return flag;
}
void dp(int x,int fa) {
	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) {
			dp(e[i].to,x);
			if (max(f[x][son[x][0]==e[i].to],f[x][2])+e[i].w+f[e[i].to][0]==ans)
				if (b[e[i].to] && b[x])
					tot++;
		}
}
int main() {
	scanf("%d",&n);
	for (int u,v,w,i=1;i<n;i++) {
		scanf("%d%d%d",&u,&v,&w);
		link(u,v,w);
	}
	dfs(1,0,0);dfs(rt,0,0);
	memset(f,0,sizeof(f));
	memset(son,0,sizeof(son));
	dfs(1,0,0);
	printf("%lld\n",ans);
	for (int i=1;i<=n;i++) b[i]=1;
	Dfs(1,0,0);
	dp(1,0);
	printf("%d",tot);
	return 0;
}

 

posted @ 2016-12-27 11:19  MashiroSky  阅读(153)  评论(1编辑  收藏  举报