[POJ3585]Accumulation Degree

题面

\(\text{Solution:}\)

有些题目不仅让我们做树型 \(\text{dp}\) ,而且还让我们换每个根分别做一次, 然后这样就愉快的 \(\text{TLE}\) 了,所以我们要用一种方法快速知道所有根的答案。

二次扫描与换根法:

就是先选任意点作根做一遍 \(\text{dp}\) ,求出相关信息,然后再从根往下 \(\text{dfs}\) ,对每一个节点往下走之前进行自顶向下的推导,计算出 "换根" 后的解。

就这题而言就是用父亲的换根后的答案来跟新自己换根前的答案,一般是 换根后父亲的答案+自己换根前的答案-自己对父亲换根后的贡献

#include <set>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <assert.h>
#include <algorithm>

using namespace std;

#define fir first
#define sec second
#define pb push_back
#define mp make_pair
#define LL long long
#define INF (0x3f3f3f3f)
#define mem(a, b) memset(a, b, sizeof (a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define Debug(x) cout << #x << " = " << x << endl
#define travle(i, x) for (register int i = head[x]; i; i = nxt[i])
#define For(i, a, b) for (register int (i) = (a); (i) <= (b); ++ (i))
#define Forr(i, a, b) for (register int (i) = (a); (i) >= (b); -- (i))
#define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
#define ____ debug("go\n")

namespace io {
    static char buf[1<<21], *pos = buf, *end = buf;
    inline char getc()
    { return pos == end && (end = (pos = buf) + fread(buf, 1, 1<<21, stdin), pos == end) ? EOF : *pos ++; }
    inline int rint() {
        register int x = 0, f = 1;register char c;
        while (!isdigit(c = getc())) if (c == '-') f = -1;
        while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getc()));
        return x * f;
    }
    inline LL rLL() {
        register LL x = 0, f = 1; register char c;
        while (!isdigit(c = getc())) if (c == '-') f = -1;
        while (x = (x << 1ll) + (x << 3ll) + (c ^ 48), isdigit(c = getc()));
        return x * f;
    }
    inline void rstr(char *str) {
        while (isspace(*str = getc()));
        while (!isspace(*++str = getc()))
            if (*str == EOF) break;
        *str = '\0';
    }
    template<typename T> 
        inline bool chkmin(T &x, T y) { return x > y ? (x = y, 1) : 0; }
    template<typename T>
        inline bool chkmax(T &x, T y) { return x < y ? (x = y, 1) : 0; }    
}
using namespace io;

const int N = 2e5 + 2;

int n, T;
int tot, head[N], ver[N<<1], nxt[N<<1], edge[N<<1];
int D[N], F[N], in[N];

void add(int u, int v, int w)
{ ver[++tot] = v, edge[tot] = w, nxt[tot] = head[u], head[u] = tot; }

void DFS(int u, int f) 
{
    D[u] = 0;
    for (int i = head[u]; i; i = nxt[i]) 
        if (ver[i] != f) 
        {
            DFS(ver[i], u);
            int v = ver[i];
            if (in[v] == 1) D[u] += edge[i];
            else D[u] += min(D[v], edge[i]);
        }
}

void DP(int u, int f) 
{
    for (int i = head[u]; i; i = nxt[i]) 
        if (ver[i] != f) 
        {
            int v = ver[i];
            if (in[u] == 1) F[v] = D[v] + edge[i];
            else F[v] = D[v] + min(F[u] - min(edge[i], D[v]), edge[i]);
            DP(v, u);
        }
}

int main() {

    T = rint();
    while (T --) 
    {
        tot = 0; mem(head, 0); mem(in, 0); mem(D, 0); mem(F, 0);

        n = rint();
        for (int i = 1; i < n; ++ i)
        {
            int u = rint(), v = rint(), w = rint();
            add(u, v, w);
            add(v, u, w);
            in[u] ++, in[v] ++;
        }

        DFS(1, 0);
        F[1] = D[1];
        DP(1, 0);
        for (int i = 1; i <= n; ++ i)
            chkmax(F[1], F[i]);
        printf("%d\n", F[1]);
    }
}
posted @ 2019-03-10 16:55  茶Tea  阅读(147)  评论(0编辑  收藏  举报