zoukankan      html  css  js  c++  java
  • 【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
    ",ans);
    	for (int i=1;i<=n;i++) b[i]=1;
    	Dfs(1,0,0);
    	dp(1,0);
    	printf("%d",tot);
    	return 0;
    }
    
  • 相关阅读:
    C# 通过 probing 指定 dll 寻找文件夹
    C# 通过 probing 指定 dll 寻找文件夹
    WPF 一个性能比较好的 gif 解析库
    WPF 一个性能比较好的 gif 解析库
    PowerShell 通过 WMI 获取系统安装的驱动
    PowerShell 通过 WMI 获取系统安装的驱动
    win10 uwp 好看的时间选择控件
    PHP ftp_ssl_connect() 函数
    PHP ftp_size() 函数
    PHP ftp_site() 函数
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6225193.html
Copyright © 2011-2022 走看看