ZOJ 3527 Shinryaku! Kero Musume(树DP)

2300 years ago, Moriya Suwako was defeated by Yasaka Kanako in the Great Suwa War. As the goddess of mountains in Gensokyo, she was planning to make
a comeback and regain faith among humans.

To achieve her great plan, she decides to build shrines in human villages. Of course, each village can bulid at most one shrine. If she builds a shrine in the i-th village,
she can get Fifaith points.

Because of geological differences and the Quantum Entanglement theory, each village has one and only one "entangled" village Pi (it is a kind of one-way relationship).
If Suwakobuilds shrines both in the i-th village and the Pi-th village, the faith she get from the i-th village will changes by Gi points (it can result to a negative value of faith
points). If she only builds a shrine in the Pi-th village, but not in the i-th village, the faith she get will not changes.

Now, please help Suwako to find out the maximal faith points she can get.

Input

There are multiple test cases. For each test case:

The first line contains an integer N (2 <= N <= 100000) indicates the number of villages in Gensokyo. Then followed by N lines, each line contains
three integers Fi (0 <= Fi <= 100000) Gi (-100000 <= Gi <= 100000) Pi (1 <= Pi <= N and Pi will
not point to the i-th village itself).

Output

For each test case, output the maximal faith points that Suwako can get.

Sample Input

2
3 -1 2
2 -2 1
4
3 -2 2
4 -3 3
2 -1 1
5 -2 2

Sample Output

3
9


题意:在N个村庄选建圣地,如果在仅在PI建,不会损失满意度,如果在PI的儿子节点

也建会损失G满意度,问你选建时的最大满意度

分析:咋一看跟普通的树DP没啥区别,设dp[i][1]:为在第i个点建的最大满意度,dp[i][0]

不在第i个点建的最大满意度,但是存在环,我们来分析这个环的特点,每个村庄仅有一个"entangled" village

也就是说连边(有向)的时候每个点仅有一个入边,如果存在环的话,只有可能从环上的点开始向环外的点

边,而且不会存在双环。所以我们就在环上选定一点,分选与不选做两次树形DP,取最大值即可。

对于不在环上的点直接拓扑排序排除掉即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
using namespace std;
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define CLEAR( a , x ) memset ( a , x , sizeof a )
typedef long long LL;
const LL INF = (1LL<<50);
typedef pair<int,int>pil;
const int maxn=1e5+100;
struct node{
    int to,next;
    int val;
}e[maxn];
int n,tot;
LL dp[maxn][2];
int head[maxn],in[maxn];
int vis[maxn],a[maxn];
void addedge(int u,int v,int w)
{
    e[tot].to=v;e[tot].next=head[u];
    e[tot].val=w;head[u]=tot++;
}
void dfs(int u,int fa)
{
    dp[u][0]=0;
    dp[u][1]=a[u];
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int to=e[i].to;
        if(to!=fa)
           dfs(to,fa);
        dp[u][0]+=max(dp[to][0],dp[to][1]);
        dp[u][1]+=max(dp[to][0],dp[to][1]+e[i].val);
    }
}
LL solve(int u)
{
    LL ans1=0,ans2=0;
    dp[u][0]=0;dp[u][1]=-INF;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        dfs(v,u);
        ans1+=max(dp[v][0],dp[v][1]);
    }
    dp[u][0]=-INF;dp[u][1]=a[u];
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        dfs(v,u);
        ans2+=max(dp[v][0],dp[v][1]+e[i].val);
    }
    return max(ans1,ans2);
}
bool ok(int u,int fa)
{
    vis[u]=1;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int to=e[i].to;
        if(to==fa)
            return true;
        if(ok(to,fa))
            return true;
    }
    return false;
}
void topsort()
{
    queue<int>q;
    for(int i=1;i<=n;i++)
        if(!in[i]) q.push(i);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=1;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to=e[i].to;
            in[to]--;
            if(!in[to])
               q.push(to);
        }
    }
}
int main()
{
    int x,y,w;
    while(~scanf("%d",&n))
    {
        CLEAR(head,-1);tot=0;
        CLEAR(vis,0);CLEAR(in,0);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&a[i],&w,&y);
            addedge(y,i,w);in[i]++;
        }
        topsort();
        LL ans=0;
        for(int i=1;i<=n;i++)
        {
           if(!vis[i]&&ok(i,i))
               ans+=solve(i);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-08 23:52:18

ZOJ 3527 Shinryaku! Kero Musume(树DP)的相关文章

[zoj 3626]Treasure Hunt I 树DP

<span style="font-family: Arial, Helvetica, Verdana, sans-serif; background-color: rgb(255, 255, 255);">Treasure Hunt I</span> Time Limit: 2 Seconds      Memory Limit: 65536 KB Akiba is a dangerous country since a bloodsucker living

ZOJ 3527

这题难在破环. 对于不是环的情况,只需按照一般的树形DP来做,一步一步往根递推就可以了.对于环,则枚举其中一点的两种情况,取或不取,然后再递推,就可以了.当到达某结点的下一结点为环开始的点时,退出即可. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int MAX=2100

ZOJ 2859 二维线段树

思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了:但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后在第二维就只有pushup操作,在第一维线段树没有pushup操作.要是在第一维也有pushup操作的话,那就不用单点查询那么慢了.不过也A了,想找题即在二维同时进行pushup和pushdown操作的. #include<iost

2010辽宁省赛 NBUT 1222 English Game【字典树+DP】

[1222] English Game 时间限制: 1000 ms 内存限制: 131072 K 链接:Click Here! 问题描述 This English game is a simple English words connection game. The rules are as follows: there are N English words in a dictionary, and every word has its own weight v. There is a wei

uva 12452 Plants vs. Zombies HD SP (树DP)

Problem I: Plants vs. Zombies HD Super Pro Plants versus Zombies HD Super Pro is a game played not a grid, but on a connected graph G with no cycles (i.e., a tree). Zombies live on edges of the tree and chew through edges so that tree falls apart! Pl

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

ZOJ3632 线段树+DP

买西瓜吃,每个西瓜有两个参数,一个是p代表价格,一个是t代表能吃几天,要求n天每天都能吃西瓜,而且如果你今天买了,以前买的还没吃完 那么都得扔了,求最小花费,还真想不到用线段树+DP,最后看了一下别人的标题,想了一下,DP方程挺好推的,线段树也只是单点查询, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #inclu

hdu 4863 Centroid of a Tree 树dp

代码来自baka.. #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<set> #include<cmath> #include<vecto

[noi2013]快餐店 基环树dp,单调队列维护最大值和次大值

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 220000 #define inf 0x3ffffffffffffffLL typedef long long ll; int v[N],e[N],ne[N],nn,w[N]; void add(int x,int y,int z){ ne[++nn