您的位置:首页 > 其它

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

2015-11-27 23:27 387 查看
题意 n个点组成一棵树, 带有点权。 求最长不降的路径的长度, 且路径上最大值最小值之差不超过D。

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

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

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

#include <bits/stdc++.h>
using namespace std;
typedef pair <int, int> pii;
const int maxn = 1e5 + 5;
vector <int> G[maxn];
int val[maxn], siz[maxn], n, D;
bool centroid[maxn];
void init() {
for (int i = 0; i < maxn; i++) {
G[i].clear();
}
memset(centroid, false, sizeof centroid);
}
void dfs(int u, int father){
siz[u] = 1;
for (int v: G[u]){
if (v != father && !centroid[v]){
dfs(v, u);
siz[u] += siz[v];
}
}
}
pii FindCentroid(int u, int father, int t) {
pii res = make_pair(INT_MAX, -1);
int s = 1, m  = 0;
for (int v: G[u]) {
if (v == father || centroid[v]) {
continue;
}
res = min(res, FindCentroid(v, u, t));
m = max(m, siz[v]);
s += siz[v];
}
siz[u] = s;
m = max(m, t-s);
return min(res, make_pair(m, u));
}
map <int, int> work;
void update(int v, int len) {
auto it = work.lower_bound(v);
if (it != work.end() && it->second >= len) {
return;
}
work[v] = len;
}
void dfs_up(int u, int father, int d) {
if (val[u] > val[father]) {
return;
}
update(val[u], d);
for (int v: G[u]) {
if (v != father && !centroid[v]) {
dfs_up(v, u, d+1);
}
}
}
int res;
void dfs_down(int u, int father, int d) {
if (val[u] < val[father]) {
return;
}
auto it = work.lower_bound(val[u]-D);
if (it != work.end()) {
res = max(res, it->second+1+d);
}
for (int v: G[u]) {
if (!centroid[v] && v != father) {
dfs_down(v, u, d+1);
}
}
}

void preSolve(int g, vector <int> &son) {
work.clear();
work[val[g]] = 0;
for (int v: son) {
if (val[v] >= val[g]) {
dfs_down(v, g, 1);
}
if (val[v] <= val[g]) {
dfs_up(v, g, 1);
}
}
}
void solve(int u) {
dfs(u, 0);
int g = FindCentroid(u, 0, siz[u]).second;
vector <int> son;
for (int v: G[g]) {
if (!centroid[v]) {
son.push_back(v);
}
}
preSolve(g, son);
reverse(son.begin(), son.end());
preSolve(g, son);
centroid[g] = true;
for (int v: G[g]) {
if (!centroid[v]) {
solve(v);
}
}
}
int main() {
// freopen("in.txt", "r", stdin);
int T, cas = 1;
scanf ("%d", &T);
while (T--) {
init();
scanf ("%d%d", &n, &D);
for (int i = 1; i <= n; i++) {
scanf ("%d", val+i);
}
for (int i = 1; i < n; i++) {
int u, v;
scanf ("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
res = 1;
solve(1);
printf("Case #%d: %d\n", cas++, res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: