POJ3585 Accumulation Degree 【树形dp】

题目链接

POJ3585

题解

-二次扫描与换根法-

对于这样一个无根树的树形dp

我们先任选一根进行一次树形dp

然后再扫一遍通过计算得出每个点为根时的答案

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define cls(s) memset(s,0,sizeof(s))
using namespace std;
const int maxn = 200005,maxm = 400005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int h[maxn],ne = 2,de[maxn];
struct EDGE{int to,nxt,w;}ed[maxm];
inline void build(int u,int v,int w){
    ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
    ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++;
    de[u]++; de[v]++;
}
int n,fa[maxn];
int d[maxn],f[maxn],g[maxn],ans;
void dfs1(int u){
    f[u] = 0;
    if (de[u] == 1 && u != 1) return;
    Redge(u) if ((to = ed[k].to) != fa[u]){
        fa[to] = u; d[to] = ed[k].w; dfs1(to);
        if (de[to] == 1) f[u] += ed[k].w;
        else f[u] += min(ed[k].w,f[to]);
    }
}
void dfs2(int u){
    g[u] = f[u];
    if (fa[u]){
        if (de[fa[u]] == 1) g[u] += d[u];
        else g[u] += min(d[u],g[fa[u]] - min(d[u],f[u]));
    }
    ans = max(ans,g[u]);
    Redge(u) if ((to = ed[k].to) != fa[u]){
        dfs2(to);
    }
}
int main(){
    int T = read();
    while (T--){
        ne = 2; cls(h); cls(de); ans = 0;
        n = read(); int a,b,w;
        for (int i = 1; i < n; i++){
            a = read(); b = read(); w = read();
            build(a,b,w);
        }
        dfs1(1);
        //REP(i,n) printf("%lld ",f[i]); puts("");
        dfs2(1);
        //REP(i,n) printf("%lld ",g[i]); puts("");
        printf("%d\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/9019025.html

时间: 2024-08-30 12:36:11

POJ3585 Accumulation Degree 【树形dp】的相关文章

题解 poj3585 Accumulation Degree (树形dp)(二次扫描和换根法)

写一篇题解,以纪念调了一个小时的经历(就是因为边的数组没有乘2 phhhh QAQ) 题目 题目大意:找一个点使得从这个点出发作为源点,流出的流量最大,输出这个最大的流量. 以这道题来介绍二次扫描和换根法 作为一道不定根的树形DP,如果直接对每个点进行DP,可能时间会炸掉 但是,优秀的二次换根和扫描法可以再O(n^2)内解决问题. 二次扫描的含义:(来自lyd 算法竞赛进阶指南) 第一次扫描:任选一个节点为根节点(我会选1)在树上进行树形DP,在回溯时,从儿子节点向父节点(从底向上)进行状态转移

poj3585 Accumulation Degree(换根dp)

传送门 换根dp板子题(板子型选手 题意: 一棵树确定源点和汇点找到最大的流量(拿出一整套最大瘤板子orz const int maxn=2e5+10; int head[maxn],tot; struct node { int nt,to;long long w; }q[2*maxn]; long long dp[maxn];int cnt[maxn]; void insert(int u,int v,long long w) { q[tot].nt=head[u];q[tot].w=w;q[

[POJ3585]Accumulation Degree

题面 \(\text{Solution:}\) 有些题目不仅让我们做树型 \(\text{dp}\) ,而且还让我们换每个根分别做一次, 然后这样就愉快的 \(\text{TLE}\) 了,所以我们要用一种方法快速知道所有根的答案. 二次扫描与换根法: 就是先选任意点作根做一遍 \(\text{dp}\) ,求出相关信息,然后再从根往下 \(\text{dfs}\) ,对每一个节点往下走之前进行自顶向下的推导,计算出 "换根" 后的解. 就这题而言就是用父亲的换根后的答案来跟新自己换根

BZOJ 1017--魔兽地图(树形DP&amp;完全背包)

1017: [JSOI2008]魔兽地图DotR Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 2674  Solved: 1041[Submit][Status][Discuss] Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars.DotR里面的英雄只有一个属性——

[POJ 3585] Accumulation Degree

[题目链接] http://poj.org/problem?id=3585 [算法] 树形DP--二次扫描与换根法 [代码] #include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio&

0x54 树形DP

树形DP我只知道千万别写森林转二叉树慢的要死 没有上司的舞会 水!裸! #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[6100];int len,last[6100]; void ins(int x,int y)

【POJ 3585】Accumulation Degree

[原题题面]传送门 [题解大意] 乍一看感觉以为网络流表示一点都不会不会不会. 然后发现可以树形dp搞一下. 再然后知道了换根dp. 设d[x]表示以x为根的子树中把x做为源点,从x出发流向子树的流量最大是多少. d[x] += min(d[y],z);(deg[y]!=1) d[x] = z; (deg[y]==1) f[x]表示以x做为源点,从x出发流向整个水系的流量最大是多少. f[y] = d[y] + min(f[x] - min(d[y],z));(deg[x]!=1) f[y] =

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

UVA-01220 Party at Hali-Bula (树形DP+map)

题目链接:https://vjudge.net/problem/UVA-1220 思路: 树形DP模板题,求最大人数很简单,难点在于如何判断最大人数的名单是否有不同的情况: 解决方法是用一个数组f[manx][2]记录该节点是否出场的情况,为真时代表有多种情况; 具体讨论: 当父节点的值加上某个子节点的值时,他的f的情况也和该子节点一样: 当某个节点dp(i, 0) == dp(i, 1), 则该节点以及它的父节点也一定有多种情况(父节点必定取其中之一). Code: 1 #include<bi