hdu5886Tower Defence(树形dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Kirito_Acmer/article/details/52596073
Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 242    Accepted Submission(s): 80


Problem Description
There was a civil war between two factions in Skyrim, a province of the Empire on the continent of Tamriel. The Stormcloaks, led by Ulfric Stormcloak, are made up of Skyrim's native Nord race. Their goal is an independent Skyrim free from Imperial interference. The Imperial Legion, led by General Tullius, is the military of the Empire that opposes the Stormcloaks and seeks to reunite and pacify the province.

The current target of General Tullius is to defend Whiterun City. Near by this city there are N towers under the Empire's control. There are N1 roads link these tower, so solders can move from any tower to another one through these roads.

In military affairs, tactical depth means the longest path between two towers of all. Larger the tactical depth is, more stable these towers are.

According to the message sent by spies, General Tullius believe that Stormcloaks is planning to attack one of these roads, and his towers would be divided into two parts. However, Tullius does not know which one, so he supposes the possibility that Stormcloaks attack these roads are the same. Now, General Tullius ask for your help, to calculate the expectation of tactical depth after this attack.

To avoid the issue of precision, you need to calculate expectationoftacticaldepth×(N1).
 

Input
The first line of input contains an integer t, the number of test cases. t test cases follow.
For each test case, in the first line there is an integer N(N100000).
The i-th line of the next N1 lines describes the i-th edge. Three integers u,v,w (0w1000) describe an edge between u and v of length w.
 

Output
For each test cases, output expectationoftacticaldepth×(N1).
 

Sample Input
2 3 2 1 2 3 2 5 5 2 1 7 3 1 7 4 2 5 5 2 6
 

Sample Output
7 63

题意:给你一棵树,树的每条边都有权值,每次等概率地切掉一条边,求所有切掉一条边后情况的直径和。

思路:和network那题一样,是树形dp,这题主要是分类讨论,有5种情况。假设现在访问的点是x,连接x的边对应的子节点是y,那么切去x-y这条边后,两部分的较大直径只可能是:1.以y为根的子树的直径。2.a,b节点是x的子节点,且lca(a,b)是x,找到满足前面条件的最长a-x-b路径。3.a是x的子节点,满足前面条件的最大的以a为根的子树。4.设x的父亲是h,从父亲节点h转移过来的树的直径(这里的直径不包括x这棵子树)5.从父亲节点过来,经过x,并且到达x子树下的最远点,这条路径的距离。

这里要开6个数组,分别是dp[x](以x为根的子树的直径),dist1[x],dist1id[x],dist2[x],dist2id[x],dist3[x],dist3id[x](x节点到其子节点的第一大,第二大,第三大距离及对应的x孩子节点的编号),dpzishu1id[x],dpzishu2id[x](表示x的子树中,不包括x节点,直径最大和次大的直径和孩子节点的编号)。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
#define lson th<<1
#define rson th<<1|1
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define Key_value ch[ch[root][1]][0]
#define maxn 100050
ll dp[maxn],dpzishu1[maxn],dpzishu2[maxn],dist1[maxn],dist2[maxn],dist3[maxn];
ll dpid[maxn],dpzishu1id[maxn],dpzishu2id[maxn],dist1id[maxn],dist2id[maxn],dist3id[maxn];
int first[maxn],tot;
ll ans;
struct edge{
    int to,next;
    ll len;
}e[2*maxn];
void addedge(int u,int v,ll len)
{
    e[tot].to=v;e[tot].len=len;e[tot].next=first[u];
    first[u]=tot++;
}

void update(int u,int v,ll len)
{
    int i,j;
    if(dist1[v]+len>=dist1[u]){
        dist3[u]=dist2[u];dist3id[u]=dist2id[u];
        dist2[u]=dist1[u];dist2id[u]=dist1id[u];
        dist1[u]=dist1[v]+len;dist1id[u]=v;
    }
    else if(dist1[v]+len>=dist2[u]){
        dist3[u]=dist2[u];dist3id[u]=dist2id[u];
        dist2[u]=dist1[v]+len;dist2id[u]=v;
    }
    else if(dist1[v]+len>=dist3[u]){
        dist3[u]=dist1[v]+len;dist3id[u]=v;
    }
}
void update1(int u,int v)
{
    int i,j;
    if(dp[v]>dpzishu1[u]){
        dpzishu2[u]=dpzishu1[u];dpzishu2id[u]=dpzishu1id[u];
        dpzishu1[u]=dp[v];dpzishu1id[u]=v;
    }
    else{
        dpzishu2[u]=dp[v];dpzishu2id[u]=v;
    }
}
void dfs1(int u,int pre)
{
    int v,i,j;
    dp[u]=dist1[u]=dist2[u]=dist3[u]=dpzishu1[u]=dpzishu2[u]=0;
    dpid[u]=dist1id[u]=dist2id[u]=dist3id[u]=dpzishu1id[u]=dpzishu2id[u]=-1;
    for(i=first[u];i!=-1;i=e[i].next){
        v=e[i].to;
        if(v==pre)continue;
        dfs1(v,u);
        update(u,v,e[i].len);
        update1(u,v);
    }
    dp[u]=max(dpzishu1[u],dist1[u]+dist2[u]);
}

void dfs2(int u,int pre,ll juli,ll zhijing)
{
    int v,i,j;
    ll zj,juli1;
    for(i=first[u];i!=-1;i=e[i].next){
        v=e[i].to;
        if(v==pre)continue;
        zj=0;
        ///2
        if(dist1id[u]==v){
            zj=dist2[u]+dist3[u];
        }
        else if(dist2id[u]==v){
            zj=dist1[u]+dist3[u];
        }
        else{
            zj=dist1[u]+dist2[u];
        }
        ///3
        if(dpzishu1id[u]==v){
            zj=max(zj,dpzishu2[u]);
        }
        else{
            zj=max(zj,dpzishu1[u]);
        }
        ///4
        zj=max(zj,zhijing);
        ///5
        if(dist1id[u]==v){
            zj=max(zj,dist2[u]+juli);
        }
        else{
            zj=max(zj,dist1[u]+juli);
        }
        ans+=max(zj,dp[v]);
        if(dist1id[u]==v)juli1=max(juli,dist2[u]);
        else juli1=max(juli,dist1[u]);
        dfs2(v,u,juli1+e[i].len,zj);
    }
}

int main()
{
    int n,m,i,j,T,c,d;
    ll f;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);

        tot=0;
        for(i=1;i<=n;i++)first[i]=-1;

        for(i=1;i<=n-1;i++){
            scanf("%d%d%lld",&c,&d,&f);
            addedge(c,d,f);
            addedge(d,c,f);
        }
        ans=0;
        dfs1(1,0);
        dfs2(1,0,0,0);
        printf("%lld\n",ans);
    }
    return 0;
}


没有更多推荐了,返回首页