树形动规专题

由于冷大佬的毒奶,我开始刷树形dp了,

先来一到签到题:[POI2011]DYN-Dynamite

我们看到最大值最小,自然地想到二分,我们二分一个最大值,题目就转化为了一个点能覆盖mid范围内的点,求要有几个点能全部覆盖所有的特殊点。想到消防局的设立:但是这道题目又不能那么做。考虑DP,设F[i]表示

以i为根节点的子树中没有被覆盖的最远的点,g[i]表示以i为根的子树中距离i最近的已设立的点(为什么要这么操作?考虑树形dp一般是倒着跑dfs的,我们抉择要不要设立点肯定要考虑距离它最远的未被覆盖的点,而距离该点较远的已设立的点一定已经在之前考虑过了)这有无后效性呢?基于一个贪心:如果F[i]==mid,我们必须选这个点(正确性显然)。最后,如果该点必须要被覆盖但g[i]>mid,我们就要更新一下f[i],最后特判一下根节点。

code:
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=700006;
int n,m;
bool pan[maxn];
struct hzw
{
    int to,next,v;
}e[maxn];
int head[maxn],cur,tot,noc[maxn],hc[maxn];
inline void add(int a,int b)
{
    e[cur].to=b;
    e[cur].next=head[a];
    head[a]=cur++;
}
inline void dfs(int s,int k,int fa)
{
    noc[s]=-0x3f3f3f3f,hc[s]=0x3f3f3f3f;
    for (int i=head[s];i!=-1;i=e[i].next)
    {
        if (e[i].to==fa) continue;
        dfs(e[i].to,k,s);
        noc[s]=max(noc[s],noc[e[i].to]+1);
        hc[s]=min(hc[s],hc[e[i].to]+1);
    }
    if (pan[s]&&hc[s]>k) noc[s]=max(noc[s],0);
    if (hc[s]+noc[s]<=k) noc[s]=-0x3f3f3f3f;
    if (noc[s]==k) {tot++;hc[s]=0,noc[s]=-0x3f3f3f3f;}
}
inline bool check(int mid)
{
    tot=0;
    dfs(1,mid,1);
    if (noc[1]>=0) tot++;
    return tot<=m;
}
int main()
{
    memset(head,-1,sizeof(head));
    cin>>n>>m;
    for (int i=1;i<=n;++i) scanf("%d",&pan[i]);
    for (int i=1,a,b;i<=n-1;++i)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    int l=0,r=n,ans=n;
    while (l<=r)
    {

        int mid=(l+r)>>1;
        if (check(mid))
        {
            r=mid-1;
            ans=min(ans,mid);
        }
        else
        {
            l=mid+1;
        }
    }
    cout<<ans;
    return 0;
}

原文地址:https://www.cnblogs.com/bullshit/p/9610156.html

时间: 2024-10-12 22:37:46

树形动规专题的相关文章

【树形动规】HDU 5834 Magic boy Bi Luo with his excited tree

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5834 题目大意: 一棵N个点的有根树,每个节点有价值ci,每条树边有费用di,节点的值只能取一次,边权每次经过都要扣,问从每一个节点开始走最大能获得的价值. 题目思路: [树形动态规划] 首先用dfs求出从根1往下走的:节点u往下走最后回到节点u的最大值g[u],节点u往下走最后不回到u的最优值和次优值f[0][u],f[1][u] 接着考虑一个节点u,除了以上的情况还有可能是往它的父亲方向走,这

[JSOI2008][BZOJ1017] 魔兽地图DotR|树形动规

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

【codevs1378】选课——树形动规

题目传送门 这道题可以用多叉树转二叉树的方法,左子树为儿子,右子树为同个父亲的兄弟,这样的话就可以很方便地写出状态转移方程: f[x][v]=max(f[x][v],w[x]+dp(ch[x][0],i)+dp(ch[x][1],v-i-1)): 要注意的是,f[x][v]可能在之前已经计算过(比如f[ch[i][0]][4]在f[i][5,6,7...]的时候就已经计算过)因此不必再计算,否则会TLE. 剩下的就不难了,直接DFS即可,具体实现细节看代码: #include<cstdio>

HDOJ1011(树形动规)

#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define max (a>b)?a:b const int nMax = 105; int map[nMax][nMax]; int d[nMax][nMax]; int visit[nMax]; struct Room { int bugs, brains; }room[nMax]; int N, M;

洛谷 P2899 [USACO08JAN]手机网络Cell Phone Network(树形动规)

题目描述 Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires him to set up cell phone towers on his N (1 ≤ N ≤ 10,000) pastures (conveniently numbered 1..N) so they can all

洛谷 P2986 [USACO10MAR]伟大的奶牛聚集(树形动规)

题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of course, she would like to choose the most convenient location for the gathering to take place. Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会

POJ 2955 Brackets (动规)

Brackets Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2999   Accepted: 1536 Description We give the following inductive definition of a "regular brackets" sequence: the empty sequence is a regular brackets sequence, if s is a reg

sicily 1091 Maximum Sum (动规)

1 //1091.Maximum Sum 2 //b(i,j) = max{b(i,j-1)+a[j], max(b(i-1,t)+a[j])} (t<j) 3 #include <iostream> 4 using namespace std; 5 6 int main() { 7 int t; 8 cin>>t; 9 while (t--) { 10 int n; 11 cin>>n; 12 int a[n+1]; 13 for (int i = 1; i &

ACM/ICPC 之 经典动规(POJ1088-滑雪)

POJ1088-滑雪 将每个滑雪点都看作起点,从最低点开始逐个由四周递推出到达此点的最长路径的长度,由该点记下. 理论上,也可以将每一点都看作终点,由最高点开始计数,有兴趣可以试试. 1 //经典DP-由高向低海拔滑雪-求最长路 2 //Memory:372K Time:32 Ms 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 using