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;
    }
    
  • 相关阅读:
    Windows性能计数器应用
    Azure Oracle Linux VNC 配置
    Azure 配置管理系列 Oracle Linux (PART6)
    Azure 配置管理系列 Oracle Linux (PART5)
    Azure 配置管理系列 Oracle Linux (PART4)
    Azure 配置管理系列 Oracle Linux (PART3)
    Azure 配置管理系列 Oracle Linux (PART2)
    vagrant多节点配置
    docker基本操作
    LINUX开启允许对外访问的网络端口命令
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6225193.html
Copyright © 2011-2022 走看看