恐怖分子炸桥

来源:互联网 发布:mysql alter trigger 编辑:程序博客网 时间:2024/06/02 14:31

HDU - 4679

题目描述:

n~1e5个点的树,边的长度都是1,但是每一条边都有一个破坏的值,恐怖分子可以随便破坏一条边,剩下两棵书的直径的较大值*破坏边的值设为t,求所有的边中最小的t对应的id,如果一样的话输出较小的id

题解:

计算一棵树上,去掉一条边之后剩下的两棵树分别的直径.首先,求u为根子树的直径很好求:先搞出来距离dpm和dps,然后再dfs之后就搞出了直径.第二:是重点.就像2说的,要去掉u,并且要考虑u的兄弟,因此我们不能定fa为f[fa],因为这样过答案f要包含fa的一些儿子,违反了2中的规则.于是定f[u],含义是去掉u本身及u的儿子之后的树的最长直径.那么下面就是如何从u推到v.看v的答案组成,包含u的答案,之后是u的非v的儿子们的最长直径,之后是和u相关的,就是u向上的最长链和u非v的两条最长链挑出两个组成.u向上的最长链经常搞.这样就搞出来了.因此需要向下的3条链,儿子中2个最大的直径.下面的代码因为只存了1个u为根直径,因此每次都要再遍历一次找出儿子的2个最大的直径….

重点:

超级多dp的树形dp
重点是从上往下的树形dp,f[u]表示的是去掉u并且去掉u的儿子们的最大直径,然后从dfs的时候u已经搞定了,去搞定v. u->推v.

代码:

#pragma comment(linker,"/STACK:102400000,102400000")#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(int i = a;i < b;i++)#define REP_D(i, a, b) for(int i = a;i <= b;i++)typedef long long ll;using namespace std;const int maxn = 1e5 + 10;const int INF= 1e9 + 100;int dp[maxn][3], n;int dia[maxn];int ans, ans_i;struct edge{    int a, b, w;};edge p[maxn];struct info{    int to, no;};vector<info> G[maxn];void gao(int &a, int &b, int &c, int t)//好写一点,更新三个大值{    if(t > a)    {        c = b;        b = a;        a = t;    }    else if(t > b)    {        c = b;        b = t;    }    else if(t > c)    {        c = t;    }}void dfs_dp(int u, int fa)//搞出3个最大的到叶子的{    for(int i = 0; i <= 2; i++)    {        dp[u][i] = 0;//初始化为0,因为只要为0,路径一定不相交    }    REP(i, 0, G[u].size())    {        int v = G[u][i].to;        if(fa!=v)        {            dfs_dp(v, u);            int tmp = dp[v][0] + 1;            gao(dp[u][0], dp[u][1], dp[u][2], tmp);        }    }}void dfs_dia(int u, int fa)//搞出u子树上的直径{    int d = 0;    dia[u] = 0;    REP(i, 0, G[u].size())    {        int v = G[u][i].to;        if(v!=fa)        {            dfs_dia(v, u);        }        d = max(d, dia[v]);    }    d = max(d, dp[u][0]+dp[u][1]);    dia[u] = d;}void dfs(int u, int fa, int u_ans, int u_l, int ans_id){    if(fa != 0)//第一次不用算结果    {//这是算结果用的,因为u的f定义已经得到答案了,因此可以算答案了.        int t = max(u_ans, dia[u])*p[ans_id].w;        if(t < ans)        {            ans = t;            ans_i = ans_id;        }        else if(t == ans)        {            ans_i = min(ans_i, ans_id);        }    }    int diam = 0, dias = 0;    int nouse = 0;    REP(i, 0, G[u].size())//先遍历一遍,如果已经存过两个直径,就不用遍历了    {        int v = G[u][i].to;        if(v==fa)            continue;        gao(diam, dias, nouse, dia[v]);    }    //int uforv_l = u_l;    REP(i, 0, G[u].size())//重点开始    {        int v = G[u][i].to;        int id = G[u][i].no;        if(v==fa)            continue;        int v_ans = u_ans;//v_ans的第一个组成        if(diam==dia[v])//第二个        {            v_ans = max(v_ans, dias);        }        else        {            v_ans = max(v_ans, diam);        }        int a, b;//第三个        if(dp[u][0]==1+dp[v][0])        {            a = dp[u][1];            b = dp[u][2];        }        else if(dp[u][1] == 1+dp[v][0])        {            a = dp[u][0];            b = dp[u][2];        }        else        {            a = dp[u][0];            b = dp[u][1];        }        v_ans = max(a+b, v_ans);        v_ans = max(a+u_l, v_ans);        dfs(v, u, v_ans, 1 + max(a, u_l), id);//v_l很容易就算出来了    }}void solve(){    dfs_dp(1, 0);    dfs_dia(1, 0);    ans = INF;    dfs(1, 0, 0, 0, 0);    printf("%d\n", ans_i);}int main(){    freopen("8Hin.txt", "r", stdin);    //freopen("6Fout.txt", "w", stdout);    int ncase;    scanf("%d", &ncase);    for(int _ = 1; _ <= ncase; _++)    {        printf("Case #%d: ", _);        scanf("%d", &n);        REP_D(i, 1, n)        {            G[i].clear();        }        REP_D(i, 1, n - 1)        {            int a, b, w;            scanf("%d%d%d", &a, &b, &w);            p[i].a=a;            p[i].b=b;            p[i].w=w;            info t;            t.to = b;            t.no = i;            G[a].push_back(t);            t.to = a;            G[b].push_back(t);        }        solve();    }    return 0;}
0 0
原创粉丝点击