POJ3585 换根模板

题意:机翻?

好,假装各位都已经看懂了题。

首先是暴力,枚举每一个点作为根,然后每次做一个树上DP,复杂度O(n2),T掉;

然后,我们考虑怎样优化。

假设我们已经求出了x的答案,对与每一个它的子节点,

我们注意到其实当我们换其子节点y为根时,y的子树贡献是已知的。

只需考虑另外一侧的贡献之间,

同时又注意到,除y以外的对x的贡献就是x的答案减掉y对它的贡献,也是一定的。

所以只有x会影响到y,直接根据限制在y和x之间转移一下就好了。

#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
inline int gi () {
    int x=0, w=0; char ch=0;
    while (! (ch>=‘0‘ && ch<=‘9‘) ) {
        if (ch==‘-‘) w=1;
        ch=getchar ();
    }
    while (ch>=‘0‘ && ch<=‘9‘) {
        x= (x<<3) + (x<<1) + (ch^48);
        ch=getchar ();
    }
    return w?-x:x;
}

const int N=2e5+10;
int T,n,tot,ans,head[N],f[N],Deg[N],ind[N],vis[N];

struct Edge {
    int next, now, val;
}e[N<<1];
inline void make (int from, int to, int va) {
    e[++tot].next=head[from];
    e[tot].now=to;
    e[tot].val=va;
    head[from]=tot;
}

void New_case () {
    tot=0; ans=0;
    memset (f, 0, sizeof (f) );
    memset (&e, 0, sizeof (e) );
    memset (ind, 0, sizeof (ind) );
    memset (vis, 0, sizeof (vis) );
    memset (Deg, 0, sizeof (Deg) );
    memset (head, 0, sizeof (head) );
}

void DP (int k) {
    vis[k]=1;
    for (int i=head[k];i;i=e[i].next) {
        int x=e[i].now;
        if (vis[x]) continue;
        DP (x);
        if (ind[x]==1) Deg[k]+=e[i].val;
        else Deg[k]+=min (Deg[x], e[i].val);
    }
}

void DFS (int p) {
    vis[p]=1;
    for (int i=head[p];i;i=e[i].next) {
        int k=e[i].now;
        if (vis[k]) continue;
        if (ind[p]==1) f[k]=Deg[k]+e[i].val;
        else f[k]=Deg[k]+min (e[i].val, f[p]-min (e[i].val, Deg[k]) );
        DFS (k);
    }
}

int main ()
{
    T=gi ();
    while (T--) {
        n=gi ();
        New_case ();
        for (int i=1, x, y, z;i<n;++i) {
            x=gi (), y=gi (), z=gi ();
            ind[x]++, ind[y]++;
            make (x, y, z);
            make (y, x, z);
        }
        DP (1);
        memset (vis, 0, sizeof (vis) );
        f[1]=Deg[1];
        DFS (1); // 换根
        for (int i=1;i<=n;++i)
            ans=max (ans, f[i]);
        printf ("%d\n", ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Bhllx/p/9807605.html

时间: 2024-10-11 00:40:13

POJ3585 换根模板的相关文章

poj3585树最大流——换根法

题目:http://poj.org/problem?id=3585 二次扫描与换根法,一次dfs求出以某个节点为根的相关值,再dfs遍历一遍树,根据之前的值换根取最大值为答案. 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,head[200005],ct,d[200005],f[200005],deg[200005],ans,t; bool v

题解 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[

换根DP

换根dp的通法:1.第一次扫描时,任选一个点为根,在"有根树"上执行一次树形DP,也就在回溯时发生的,自底向上的状态转移. 2.第二次扫描时,从刚才选出的根出发,对整棵树执行一次dfs,在每次递归前进行自上向下的推导,计算出换根后的解. 1.POJ3585 Accumulation Degree dp[i]以i为根的子树中,把i作为源点的最大流量 转移\(dp[x]=\sum_{y\epsilon son(x)}^{}\left\{\begin{matrix} min(dp[y],le

遥远的国度(树链剖分,换根)

遥远的国度 题目描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀. 问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树.这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的.遥远的国度的每个城市有一个防御值,有些时候RapiD会使

cf219d 基础换根法

/*树形dp换根法*/ #include<bits/stdc++.h> using namespace std; #define maxn 200005 struct Edge{int to,nxt,flag;}edge[maxn<<1]; int root,n,s,t,head[maxn],tot,dp[maxn]; void init(){ memset(head,-1,sizeof head); tot=0; } void addedge(int u,int v,int fl

不知哪个OJ 小x游世界树 换根?不知。

小x游世界树 (yggdrasi.pas/c/cpp) [问题描述] 小x得到了一个(不可靠的)小道消息,传说中的神岛阿瓦隆在格陵兰海的某处,据说那里埋藏着亚瑟王的宝藏,这引起了小x的好奇,但当他想前往阿瓦隆时发现那里只有圣诞节时才能到达,然而现在已经春天了,不甘心的他将自己的目的地改成了世界树,他耗费了大量的时间,终于将自己传送到了世界树下.世界树是一棵非常巨大的树,它有着许许多多的枝条以及节点,每个节点上都有一个平台.好不容易来到传说中的世界树下,小x当然要爬上去看看风景.小x每经过一条边都

肥宅快乐树 换根+树形DP/dfs

肥宅快乐树是一棵神秘而巨大的树,它长有许多枝条和节点,每条枝连接树中两个节点,每个节点上都长有一瓶肥宅快乐水. 何老板是肥宅快乐水的资深爱好者.历经艰难,他终于找到了这棵传说中的快乐树.他想要获取树上所有的快乐水,迫不及待地想从树根往树上爬. 每经过一条树枝都会耗费一定体力.而且快乐树自带防御功能,即每条枝上都有一个一次性陷阱,一旦踏上该枝,何老板就会被立即弹射回地面,他得重新从根往上爬. (注1:一次性陷阱是指,陷阱只在第一次经过该枝时有效) (注2:从i号点回到i的父亲节点,不耗费体力) 每

【换根dp】9.22小偷

换根都不会了 题目大意 给定一棵$n$个点的树和树上一撮关键点,求到所有$m$个关键点距离的最大值$dis_{max}\le LIM$的点的个数. $n,m\le 30000,LIM\le 30000$ 题目分析 考虑在求出一个点的情况下如何转移到其子节点. 对点$u$最直接关心的状态是$mx[u]$:所有关键点到$u$的最大距离. 对点$u$的子节点$v$来说,$u$能带给它的只是“外面的世界”——$v$子树的补集这块贡献,也就是对于$u$的除了$v$子树的$mx[u]$. 因为$mx[u]$