题目链接
https://www.luogu.org/problemnew/show/P1084
这个很考码力……
写得我………………
大致思路
一般关于时间都有一个隐含的最大值
然后又是最小时间
所以就是最大值最小,二分答案
二分出时间后
就让每个军队尽量往上跳
跳不到根节点就停在那了
如果跳的到根节点,就记录到根节点还能再跳多少,按照这个值排序
然后把还没被控制的子树记录一下
然后按照距离排序
然后就贪心,就是让路程剩余值最小的去覆盖子树距离最小的,这样不会浪费,
留下剩余值大的去覆盖子树距离大的
注意这个时候如果子树在该点跳到根节点的路径时,就直接跳回去
关于二分答案的思路
一般题目是从条件出发,当达到题目要求的时候可以推出答案。
而二分答案就是从答案出发,利用条件来判断看可不可以达到题目要求。
思维一定要换过来。
一些细节
(1)写递归函数的时候,不要下意识的写dfs,比如这道题的push_up函数往下的时候我就写成dfs了,而且我静态差错还没查出来
(2)这道题可以设1的根节点为0,向上跳的时候注意判断
(3)注意大于和不等于的区别
(4)判断是否是叶子节点可以用一个变量来表示,不需要记录度数
(5)二分中的check函数因为要执行很多次所以要记得初始化
(6)写结构体的时候记得内部加分号,每次都不加……
(7)这道题注意long long(不用也能过??)
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; typedef long long ll; const int MAXN = 5e5 + 10; const int MAXM = 20; struct Edge{ int to, w, next; }; Edge e[MAXN << 1]; int head[MAXN], tot; ll dis[MAXN][MAXM + 5]; int f[MAXN][MAXM + 5], st[MAXN]; int vis[MAXN], n, m, cnt; void AddEdge(int from, int to, int w) { e[tot] = Edge{to, w, head[from]}; head[from] = tot++; } void read(int& x) { int f = 1; x = 0; char ch = getchar(); while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); } while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } x *= f; } void dfs(int u, int fa) { for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if(v == fa) continue; dfs(v, u); f[v][0] = u; dis[v][0] = e[i].w; } } void push_up(int u, int fa) { bool ok = 1, p = 0; for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if(v == fa) continue; push_up(v, u); if(!vis[v]) ok = 0; p = 1; } if(u != 1 && ok && p) vis[u] = 1; } struct node { int id; ll w; bool operator < (const node& rhs) const { return w < rhs.w; } }; vector<node> v1; vector<node> v2; bool check(ll ans) { memset(vis, 0, sizeof(vis)); v1.clear(); v2.clear(); _for(i, 1, m) { int u = st[i]; ll dist = 0; for(int j = MAXM; j >= 0; j--) if(f[u][j] && dist + dis[u][j] <= ans) dist += dis[u][j], u = f[u][j]; if(u != 1) vis[u] = 1; else { u = st[i]; for(int j = MAXM; j >= 0; j--) if(f[u][j] > 1) //这里是大于不是不等于 u = f[u][j]; v1.push_back(node{u, ans - dist}); } } push_up(1, 0); for(int i = head[1]; ~i; i = e[i].next) { int v = e[i].to; if(!vis[v]) v2.push_back(node{v, e[i].w}); } sort(v1.begin(), v1.end()); sort(v2.begin(), v2.end()); int j = 0; REP(i, 0, v1.size()) { if(!vis[v1[i].id]) vis[v1[i].id] = 1; else if(v1[i].w >= v2[j].w) vis[v2[j].id] = 1; while(j < v2.size() && vis[v2[j].id]) j++; if(j == v2.size()) return true; } return false; } int main() { ll l = -1, r = 0; memset(head, -1, sizeof(head)); tot = 0; read(n); REP(i, 1, n) { int u, v, w; read(u); read(v), read(w); AddEdge(u, v, w); AddEdge(v, u, w); if(u == 1 || v == 1) cnt++; r += w; } dfs(1, 0); f[1][0] = 0; _for(j, 1, MAXM) _for(u, 1, n) { f[u][j] = f[f[u][j-1]][j-1]; dis[u][j] = dis[u][j-1] + dis[f[u][j-1]][j-1]; } read(m); _for(i, 1, m) read(st[i]); if(m < cnt) { puts("-1"); return 0; } while(l + 1 < r) { int m = (l + r) >> 1; if(check(m)) r = m; else l = m; } printf("%d ", r); return 0; }