UVALive 7148 LRIP 14年上海区域赛K题 树分治

题意 n个点组成一棵树, 带有点权。 求最长不降的路径的长度, 且路径上最大值最小值之差不超过D。

显然是树分治, 但是分治之后如何维护答案呢。

假设当前重心为g, 分别记录g出发不降路径的长度,以及最大值, 和不升路径的长度以及最小值。

这里用到一个map和二分, 线段树也可以, 但是如果用线段树还要考虑负值, 再加上线段树的clear以及稍微暴力的查询。  常数大小不好说。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef pair <int, int> pii;
  4 const int maxn = 1e5 + 5;
  5 vector <int> G[maxn];
  6 int val[maxn], siz[maxn], n, D;
  7 bool centroid[maxn];
  8 void init() {
  9     for (int i = 0; i < maxn; i++) {
 10         G[i].clear();
 11     }
 12     memset(centroid, false, sizeof centroid);
 13 }
 14 void dfs(int u, int father){
 15     siz[u] = 1;
 16     for (int v: G[u]){
 17         if (v != father && !centroid[v]){
 18             dfs(v, u);
 19             siz[u] += siz[v];
 20         }
 21     }
 22 }
 23 pii FindCentroid(int u, int father, int t) {
 24     pii res = make_pair(INT_MAX, -1);
 25     int s = 1, m  = 0;
 26     for (int v: G[u]) {
 27         if (v == father || centroid[v]) {
 28             continue;
 29         }
 30         res = min(res, FindCentroid(v, u, t));
 31         m = max(m, siz[v]);
 32         s += siz[v];
 33     }
 34     siz[u] = s;
 35     m = max(m, t-s);
 36     return min(res, make_pair(m, u));
 37 }
 38 map <int, int> work;
 39 void update(int v, int len) {
 40     auto it = work.lower_bound(v);
 41     if (it != work.end() && it->second >= len) {
 42         return;
 43     }
 44     work[v] = len;
 45 }
 46 void dfs_up(int u, int father, int d) {
 47     if (val[u] > val[father]) {
 48         return;
 49     }
 50     update(val[u], d);
 51     for (int v: G[u]) {
 52         if (v != father && !centroid[v]) {
 53             dfs_up(v, u, d+1);
 54         }
 55     }
 56 }
 57 int res;
 58 void dfs_down(int u, int father, int d) {
 59     if (val[u] < val[father]) {
 60         return;
 61     }
 62     auto it = work.lower_bound(val[u]-D);
 63     if (it != work.end()) {
 64         res = max(res, it->second+1+d);
 65     }
 66     for (int v: G[u]) {
 67         if (!centroid[v] && v != father) {
 68             dfs_down(v, u, d+1);
 69         }
 70     }
 71 }
 72 
 73 void preSolve(int g, vector <int> &son) {
 74     work.clear();
 75     work[val[g]] = 0;
 76     for (int v: son) {
 77         if (val[v] >= val[g]) {
 78             dfs_down(v, g, 1);
 79         }
 80         if (val[v] <= val[g]) {
 81             dfs_up(v, g, 1);
 82         }
 83     }
 84 }
 85 void solve(int u) {
 86     dfs(u, 0);
 87     int g = FindCentroid(u, 0, siz[u]).second;
 88     vector <int> son;
 89     for (int v: G[g]) {
 90         if (!centroid[v]) {
 91             son.push_back(v);
 92         }
 93     }
 94     preSolve(g, son);
 95     reverse(son.begin(), son.end());
 96     preSolve(g, son);
 97     centroid[g] = true;
 98     for (int v: G[g]) {
 99         if (!centroid[v]) {
100             solve(v);
101         }
102     }
103 }
104 int main() {
105    // freopen("in.txt", "r", stdin);
106     int T, cas = 1;
107     scanf ("%d", &T);
108     while (T--) {
109         init();
110         scanf ("%d%d", &n, &D);
111         for (int i = 1; i <= n; i++) {
112             scanf ("%d", val+i);
113         }
114         for (int i = 1; i < n; i++) {
115             int u, v;
116             scanf ("%d%d", &u, &v);
117             G[u].push_back(v);
118             G[v].push_back(u);
119         }
120         res = 1;
121         solve(1);
122         printf("Case #%d: %d
", cas++, res);
123     }
124     return 0;
125 }
原文地址:https://www.cnblogs.com/oneshot/p/5001967.html