codeforces 743D - Chloe and pleasant prizes(树形DP)

题意

给一颗树取出两个不相互包含的子树使权值和最大



当然是选择DP辣~很容易想到枚举以每一个点为根的子树 找到对于这棵子树来说,之外的权值和最大的子树。第一遍dfs可以找出每个点的子树大小以及以每个点为根 所有子树的最大子树,以及这个子树所在的这个点的儿子节点,以及其他个儿子节点找一颗第二大子树。

所以对于每一个树来说,与它对应的最大的  另一棵最大权值子树    在父亲节点对应的最大权值子树    以及    父亲节点的另外孩子包含的最大子树上(感觉有点绕==

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define F    first
#define S     second
#define mem(a,b)    memset(a,b,sizeof(a))
using namespace std;
#define INF        0x7ffffffffffffff
typedef long long int LL;
#define MAX_N        200005
LL w[MAX_N];
struct no
{
    int v,nexr;
}ed[MAX_N*3];
int stu[MAX_N];
int col = 0;
void add(int u , int v){
    ed[col].v = v;
    ed[col].nexr = stu[u];
    stu[u] = col++;
}
pair<LL,pair<LL,LL> > ans[MAX_N];
bool flag[MAX_N];
int set[MAX_N];
int cnt[MAX_N];
void dfs(int u){
    flag[u] = true;
    ans[u].F = w[u];
    for (int i = stu[u]; i != -1  ; i = ed[i].nexr)
    {
        int v = ed[i].v;
        if(flag[v])
            continue;
        dfs(v);
        ans[u].F+=ans[v].F;
        if(ans[v].S.F>ans[u].S.F||ans[v].F>ans[u].S.F){
            set[u]  = v;
            ans[u].S.S = ans[u].S.F;
            ans[u].S.F = max(ans[v].S.F, ans[v].F);
        }
        else if(ans[v].S.F>ans[u].S.S||ans[v].F>ans[u].S.S){
            ans[u].S.S = max(ans[v].S.F,ans[v].F);
        }
    }
}
LL res[MAX_N];
void dfs2(int u){
    flag[u] = true;
    for (int i = stu[u]; i != -1  ; i = ed[i].nexr)
    {
        int v = ed[i].v;
        if(flag[v])
            continue;
        if(set[u] != v)
            res[v] = max (ans[u].S.F,res[u]);
        else
            res[v] = max (ans[u].S.S,res[u]);
        dfs2(v);
    }
}

int main(int argc, char const *argv[])
{
    int n;
    mem(stu,-1);
    scanf("%d",&n);
    for (int i = 1; i <= n ; ++i){
        scanf("%I64d",&w[i]);
        ans[i].F = ans[i].S.F = ans[i].S.S = res[i] = -INF;
    }
    int u , v;
    for (int i = 1; i <= n-1 ; ++i)
    {
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
        cnt[u]++;
        cnt[v]++;
    }
    dfs(1);
    mem(flag,false);
    dfs2(1);
    LL pri = -INF;
    for (int i = 1; i <= n ; ++i)
    {
        if(res[i]!=-INF){
            pri = max(res[i]+ans[i].F,pri);
        }
    }
    if(pri==-INF)
        printf("Impossible\n");
    else
        printf("%I64d\n",pri );
    return 0;
}
时间: 2024-10-22 20:24:16

codeforces 743D - Chloe and pleasant prizes(树形DP)的相关文章

codeforce 743D. Chloe and pleasant prizes 树dp

D. Chloe and pleasant prizes 题意:一颗以1为根的有根树,每个节点有点权,从中选出2个无相交的子树,使其权值和最大 思路:树dp裸题 dp[u][1] 记录以u为根 选一颗子树的最大值(包括u本身) dp[u][2]记录以u为根 选2颗树的最大值 dp[1][2] 即是答案 AC代码: #include "iostream" #include "string.h" #include "stack" #include &

codeforces 161D - Distance in Tree(树形dp)

题目大意: 求出树上距离为k的点对有多少个. 思路分析: dp[i][j] 表示 i 的子树中和 i 的距离为 j 的点数有多少个.注意dp[i] [0] 永远是1的. 然后在处理完一颗子树后,就把自身的dp 更新. 更新之前更新答案. 如果这颗子树到 i 有 x 个距离为j的.那么答案就要加上 dp[i] [ k-j-1] * x; #include <iostream> #include <cstdio> #include <cstring> #include &l

Codeforces 743D:Chloe and pleasant prizes(树形DP)

http://codeforces.com/problemset/problem/743/D 题意:求最大两个的不相交子树的点权和,如果没有两个不相交子树,那么输出Impossible. 思路:之前好像也做过这种类型的题目啊,知道是树形DP,但是不知道怎么保证两个不相交.看别人代码之后, 在DFS回溯的时候, 1 void dfs(int u, int fa) { 2 sum[u] = w[u]; 3 for(int i = head[u]; ~i; i = edge[i].nxt) { 4 i

CodeForces 219D.Choosing Capital for Treeland (树形dp)

题目链接: http://codeforces.com/contest/219/problem/D 题意: 给一个n节点的有向无环图,要找一个这样的点:该点到其它n-1要逆转的道路最少,(边<u,v>,如果v要到u去,则要逆转该边方向)如果有多个这样的点,则升序输出所有 思路: 看了三篇博客,挺好的 http://blog.csdn.net/chl_3205/article/details/9284747 http://m.blog.csdn.net/qq_32570675/article/d

Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]

题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_dis[i],维护非子树节点中距离该点的最大值fa_dis[i]; 2.对于每个节点维护它最大的三个儿子节点的son_dis; 3.维护up[i][j]和down[i][j]数组,这个类似倍增lca里边的fa[i][j],up[i][j]代表的含义是从第j个点向上到它的第2^i个父节点这条链上的点除了该

Codeforces 671D. Roads in Yusland(树形DP+线段树)

调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果我们枚举每条路去转移,会发现这条路沿线上的其他子树的答案难以统计,那怎么办呢,我们可以让这条路向上回溯的时候顺便记录一下,于是有$val[i]$表示必修i这条路,并且修完当前子树的最小代价. 则有转移$dp[x]=min(val[j])$,且$j$这条路必须覆盖$x$. $val[i]=(\sum

codeforces 337D D. Book of Evil(树形dp)

题目链接: codeforces 337D 题目大意: 给出一棵树,给出感染物的感染范围,给出一些已经确定被感染的点,问感染物可能放置的点的个数. 题目分析: 定义状态dp[i]代表某个点到达离它最远的确定的感染点的距离. 然后我们首先dfs一遍,求得以1为根的树,每个点到子树中的感染点的最大距离,然后再dfs一遍,求得dp[i]所要求的值,利用一个dd[i]数组表示第i点的父亲,除了自己及以自己为根的子树的点的感染点到自己的最远距离. 然后处理出来每个点儿子的前缀和后缀的最大值,然后利用dd就

Codeforces 815C. Karen and Supermarket【树形DP】

LINK 思路 首先发现依赖关系是一个树形的结构 然后因为直接算花多少钱来统计贡献不是很好 因为数组开不下 那就可以算一个子树里面选多少个的最小代价就可以了 注意统计贡献的时候用优惠券的答案只能在1号点进行统计 //Author: dream_maker #include<bits/stdc++.h> using namespace std; //---------------------------------------------- //typename typedef long lon

Codeforces Round #168 (Div. 1)B 树形dp

//给一棵树,每次操作可以将包括顶点1的连通子集的所有点的节点加1或减1 //问最少几次操作使得这棵树的所有顶点的值都为0 //以1为根节点建树 //将加和减分开考虑,用up[u],down[u]表示以u为跟节点的子树中需要加的操作 //最大为up[u] ,需要减的操作最大为down[u] //其余的加和减的操作则可以在处理这两个操作时一起覆盖 //在将u的子数全都处理完后u点的值由于在加了up[u]和减了down[u]后变为 //一个新的值,则对于这个新的值根据它的正负并入up[u]或down