zoukankan      html  css  js  c++  java
  • ZOJ 3949 Edge to the Root( 树形dp)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3949

    题解:树dp真的很直觉,或者说dp真的很直觉。就上周末比赛时其实前一半的观察我都找到了,也感觉就是O(N)的,但就是不会转移。观察其实就是说这条边会使得x这个子树的距离变少,以及从1到x这条链的中点+1的这个点的子树的距离变少。那么怎么从fa(x)转移过来呢。对于dep[x]/2+1的子树,因为x相对于fa(x)变深了,所以子树内的每一个都要+1,然而对于x的子树中的每一个点深度相对于从fa(x)变浅了所以-1,那么也就等价一个+1,一个-2。然后记录答案的那个数组要开ll。PS:为什么会有第一发超时,第二发AC的操作,也许有点小卡常。。。这好像是我第一次在ZOJ上交题诶。代码不长,想了很久。

    #include<bits/stdc++.h>
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define ls (x<<1)
    #define rs (x<<1|1)
    #define all(x)	x.begin(),x.end()
    #define ll long long
    #define For(i,a,b) for(int i=a;i<=b;i++)
    #define Forr(i,a,b) for(int i=a;i>=b;i--)
    #define Fr(i,a,b) for(int i=a;i<b;i++)
    #define Frr(i,a,b) for(int i=a;i>b;i--)
    #define pll pair<ll,ll>
    using namespace std;
    const int maxn=2e5+100;
    const ll inf=0x3f3f3f3f;
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int T;
    int n;
    int siz[maxn],depth[maxn];
    int d[maxn];
    ll ans[maxn];
    vector<int>vec[maxn];
    void dfs(int x,int fa)
    {
    	siz[x]=1;depth[x]=depth[fa]+1;
    	for(int i=0;i<vec[x].size();i++){
    		int tt=vec[x][i];
    		if(tt!=fa){
    			dfs(tt,x);
    			siz[x]+=siz[tt];
    		}
    	}
    }
    void dfs1(int x,int fa)
    {	
    	d[depth[x]]=x;
    	int tt=depth[x]/2+1;
    	if(fa==0||fa==1){
    		ans[x]=ans[1];
    	}
    	else
    	{
    		ans[x]=ans[fa]+siz[d[tt]]-2*siz[x];	
    	}
    	for(int i=0;i<vec[x].size();i++)
    	{
    		int tk=vec[x][i];
    		if(tk!=fa)dfs1(tk,x);
    	}
    }
    int main()
    {
    	int p,q;
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d",&n);
    		for(int i=1;i<=n;i++)vec[i].clear();
    		for(int i=1;i<n;i++)
    		{
    			scanf("%d",&p);scanf("%d",&q);
    			vec[p].pb(q);vec[q].pb(p);
    		}
    		depth[0]=-1;
    		dfs(1,0);
    		ans[1]=0;
    		for(int i=2;i<=n;i++)ans[i]=1e18;
    		for(int i=1;i<=n;i++)ans[1]+=depth[i];
    		//cout<<ans[1]<<"
    ";
    		dfs1(1,0);
    		ll res=ans[1];
    		for(int i=2;i<=n;i++)res=min(res,ans[i]);
    		printf("%lld
    ",res);
    	}	
    }
    

      

  • 相关阅读:
    调试 Android* x86 应用程序的方法以及要使用的工具
    android 获取手机信息工具类
    Android 布局自适应屏幕
    php &amp; 和 &amp;amp; (主要是url 问题)
    系统的BIOS与系统安装
    ios的设计原则
    POJ 2409 Let it Bead(Polya简单应用)
    鸿学金信风控具体介绍
    Linux高性能server编程——I/O复用
    WCF问题集锦:未依照DataMember定义的名称序列化对象
  • 原文地址:https://www.cnblogs.com/intwentieth/p/10575100.html
Copyright © 2011-2022 走看看