HNOI2003 消防局的设立
这道题似乎是夹克老爷的愤怒那道题的弱化版……?这次的距离是固定为2的。
我们首先考虑一下只有一条链的情况,这个谁都会,就是每隔2k(k为给定距离)个点放一个,就是这样贪心。树也可以用这种贪心法来求解,我们从叶子节点往上DP,每次用dp[i]表示这个点还能往上控制距离为多少的点,如果当前的dp值为-2的话,就新建立一个消防局,并把dp值改为2,同时还要记录当前点所有子节点dp值的最大和最小值,如果二者和大于零,那就说明这个点可以被自己的某个子节点控制,那么dp值就是最大值-1,否则的话,dp值就是最小值-1。
这样直接dp即可,最后到根节点的时候,如果dp值小于0,那么还需要多建立一个消防局。
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 100005; const int INF = 1000000009; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct edge { int next,to; }e[M]; int n,head[M],ecnt,dp[M],x,y,ans; void add(int x,int y) { e[++ecnt].to = y; e[ecnt].next = head[x]; head[x] = ecnt; } void dfs(int x,int fa) { int minn = INF,maxn = -INF; for(int i = head[x];i;i = e[i].next) { if(e[i].to == fa) continue; dfs(e[i].to,x); minn = min(minn,dp[e[i].to]); maxn = max(maxn,dp[e[i].to]); } if(minn == INF) dp[x] = -1; else if(minn <= -2) ans++,dp[x] = 2; else if(minn + maxn > 0) dp[x] = maxn - 1; else dp[x] = minn - 1; } int main() { n = read(); rep(i,2,n) x = read(),add(i,x),add(x,i); dfs(1,1); if(dp[1] < 0) ans++; printf("%d\n",ans); return 0; }
当你意识到,每个上一秒都成为永恒。