【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; }
This passage is made by MashiroSky.