bzoj3124[Sdoi2013]直径(树dp)

Description

小Q最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有N个节点,可以证明其有且仅有N-1 条边。 路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b)
表示点a和点b的路径上各边长度之和。称dis(a,b)为a、b两个节点间的距离。
直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。
现在小Q想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。

Input

第一行包含一个整数N,表示节点数。
接下来N-1行,每行三个整数a, b, c ,表示点 a和点b之间有一条长度为c
的无向边。

Output

共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有
直径经过的边的数量。

Sample Input

6
3 1 1000
1 4 10
4 2 100
4 5 50
4 6 100

Sample Output

1110
2

第一问很简单,两边dfs即可。
对于第二问,我们需要注意到以下几点
(设直径较浅的端点为 up ,较深的端点为 low , dp[x] x up 的路径长度)
1.答案一定在已经确定出的直径上
2.当存在一段由 u v 的最长路径 dis ,使得 dis==dp[x] (dis==dp[low]dp[x]) 时,x以上(以下)的路径全部变为不合法.
所以我们可以先求出一条直径,同时dp出不与直径相交的最长路径长度,然后统计出合法区间中的点数即可.
代码

#include 
#include 
#define maxn 200005
#define maxx 400005
#define mem(a,b) memset(a,b,sizeof(a))
inline void read(int& x)
{   char c=getchar();x=0;int y=1;
    while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    x*=y;
}
typedef long long ll;
ll dp[maxn],f[maxn],ans;
int n,num,hea[maxn],lef[maxn],rig[maxn],cnt,range,target,retarget,upside,downside;
bool used;
struct road{int en,w,nex;}ro[maxx];
inline void add(int x,int y,int z){ro[num].en=y;ro[num].nex=hea[x];ro[num].w=z;hea[x]=num++;}
inline void dfs(int x,int y=0,ll z=0)
{   if(z>ans) ans=z,target=x;
    for(int i=hea[x];i!=-1;i=ro[i].nex)
    {   int v=ro[i].en;
        if(v==y) continue;
        dfs(v,x,z+ro[i].w);
    }
}
inline void redfs(int x,int y=0,ll z=0)
{   lef[x]=rig[x]=++cnt;dp[x]=z;
    if(ansfor(int i=hea[x];i!=-1;i=ro[i].nex)
    {   int v=ro[i].en;
        if(v==y) continue;
        redfs(v,x,z+ro[i].w);
        if(f[x]inline void dfs3(int x,int y=0)
{   ll fir=0;
    for(int i=hea[x];i!=-1;i=ro[i].nex)
    {   int v=ro[i].en;if(v==y) continue;
        if(lef[v]<=range&&rig[v]>=range) dfs3(v,x);
        else if(firif(!used&&fir==dp[x]) upside=x,used=1;
    if(fir==(dp[retarget]-dp[x])) downside=x;
}
inline void dfs4(int x,int y=0)
{   if(dp[x]>=dp[upside]&&dp[x]<=dp[downside]) ++ans;
    for(int i=hea[x];i!=-1;i=ro[i].nex)
    {   int v=ro[i].en;if(v==y) continue;
        if(lef[v]<=range&&rig[v]>=range) dfs4(v,x);
    }
}
int main()
{   read(n);mem(hea,-1);int x=0,y=0,z=0;
    for(int i=1;i1);ans=0;redfs(target);printf("%lld\n",ans);
    dfs3(target);ans=0;dfs4(target);
    printf("%lld",ans-1);
    return 0;
}

你可能感兴趣的:(dp)