zoukankan      html  css  js  c++  java
  • 【BZOJ3302】[Shoi2005]树的双中心 DFS

    【BZOJ3302】[Shoi2005]树的双中心

    Description

    Input

    第一行为N,1<N<=50000,表示树的节点数目,树的节点从1到N编号。
    接下来N-1行,每行两个整数U,V,表示U与V之间有一条边。
    再接下N行,每行一个正整数,其中第i行的正整数表示编号为i的节点权值为W(I),树的深度<=100

    Output

    将最小的S(x,y)输出,结果保证不超过19^9

    Sample Input

    5
    1 2
    1 3
    3 4
    3 5
    5
    7
    6
    5
    4

    Sample Output

    14

    HINT

    选取两个中心节点为2,3

    题解:这题的做法还是挺神的~

    有一种暴力的方法:先枚举一条边,将这条边断开,然后两边分别求重心,但是这样做复杂度有点高。

    如何优化呢?观察到树高只有300,所以我们可以从树根开始,不断向靠近重心的方向移动,不能移动时就找到了重心,复杂度是树高级别的,可以通过此题。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    using namespace std;
    const int maxn=50010;
    typedef long long ll;
    int n,cnt;
    int head[maxn],to[maxn<<1],next[maxn<<1],fa[maxn],ins[maxn];
    ll siz[maxn],f[maxn][2],g[maxn];
    ll tot,now,ans,sz;
    inline void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    inline ll rd()
    {
    	ll ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void dfs1(int x)
    {
    	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=fa[x])
    	{
    		fa[to[i]]=x,dfs1(to[i]),siz[x]+=siz[to[i]],g[x]+=g[to[i]]+siz[to[i]];
    		if(siz[to[i]]>siz[f[x][0]])	f[x][1]=f[x][0],f[x][0]=to[i];
    		else	f[x][1]=(siz[f[x][1]]>siz[to[i]])?f[x][1]:to[i];
    	}
    }
    inline ll calc(int x,int y)
    {
    	ll sy=siz[y]-(ins[y])*sz;
    	return now-2*sy+tot;
    }
    void dfs3(int x)
    {
    	ll t1=calc(x,f[x][0]),t2=calc(x,f[x][1]);
    	if(t1<t2)
    	{
    		if(t1<now)	now=t1,dfs3(f[x][0]);
    	}
    	else	if(t2<now)	now=t2,dfs3(f[x][1]);
    }
    void dfs2(int x,int dep)
    {
    	ins[x]=1;
    	if(x!=1)
    	{
    		ll tmp=0;
    		tot=siz[x],sz=0,now=g[x],dfs3(x),tmp+=now;
    		tot=siz[1]-siz[x],sz=siz[x],now=g[1]-g[x]-dep*siz[x],dfs3(1),tmp+=now;
    		ans=min(ans,tmp);
    	}
    	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=fa[x])	dfs2(to[i],dep+1);
    	ins[x]=0;
    }
    int main()
    {
    	n=rd();
    	int i,a,b;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
    	for(i=1;i<=n;i++)	siz[i]=rd();
    	dfs1(1),ans=g[1],dfs2(1,0);
    	printf("%lld",ans);
    	return 0;
    }
  • 相关阅读:
    SPOJ SAMER08A
    SPOJ TRAFFICN
    CS Academy Set Subtraction
    CS Academy Bad Triplet
    CF Round 432 C. Five Dimensional Points
    CF Round 432 B. Arpa and an exam about geometry
    SPOJ INVCNT
    CS Academy Palindromic Tree
    身体训练
    简单瞎搞题
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7536476.html
Copyright © 2011-2022 走看看