spoj FTOUR2(树的分治)

来源:互联网 发布:封锁 张爱玲 知乎 编辑:程序博客网 时间:2024/06/01 10:38

题目链接

QZC树的分治论文第二道例题, 自己想了想觉得没什么思路, 后来看了论文中的解法看到中间时想到了一个线段树优化dp的解法, 论文中也提到的令dp[L] 表示从当前根结点向下经过L个crowded节点的最长路径值,在进行分治时用两个dp数组, dp1表示当前根节点前i - 1棵子树的dp值, dp2表示第i棵子树的dp值,用线段树维护dp1的值,我们每次dfs一个子树时得到dp2的值, 然后用

dp2[j] + max(dp1[k]) 0 <= k <= m - j - is[root]( m表示最多经过m个crowed节点)更新ans, 然后再用dp2更新dp1, 大致就是这样的一个做法。。。


#include <iostream>#include <cstdio>#include <queue>#include <map>#include <algorithm>#include <cstring>#include <cstdlib>using namespace std;typedef long long LL;inline int readint() {char c = getchar();while (!isdigit(c)) c = getchar();int x = 0;while (isdigit(c)) {x = x * 10 + c - '0';c = getchar();}return x;}inline int lowbit(int t) {return t & (-t);}const int N = 200015;const int M = N << 1;const int INF = 2000000001;#define fi first#define se secondint n, is[N];int head[N], next[M], to[M], W[M];bool done[N];int size[N], d[N];int dp1[N], dp2[N];int sub[N];int E, tot, root, tdfn;int K;vector<int> vec;int ans;#define lch rt << 1, L, mid#define rch rt << 1 | 1, mid + 1, Rstruct SegmentTree {int maxv[N << 2];int n;void init(int n) {this->n = n;build(1, 0, n);}inline void push_up(int rt) {maxv[rt] = max(maxv[rt << 1], maxv[rt << 1 | 1]);}void build(int rt, int L, int R) {if (L == R) {maxv[rt] = dp1[L];return;}int mid = L + R >> 1;build(lch), build(rch);push_up(rt);}void update(int rt, int L, int R, int p, int v) {if (L == R) {maxv[rt] = v;return;}int mid = L + R >> 1;if (p <= mid)update(lch, p, v);elseupdate(rch, p, v);push_up(rt);}int query(int rt, int L, int R, int l, int r) {if (l <= L && R <= r) {return maxv[rt];}int mid = L + R >> 1;int res = -INF;if (l <= mid)res = max(res, query(lch, l, r));if (r > mid)res = max(res, query(rch, l, r));return res;}void op1(int p, int v) {update(1, 0, n, p, v);}int op2(int l, int r) {if (l > r)return -INF;return query(1, 0, n, l, r);}}T;void init() {for (int i = 1; i <= n; i++)head[i] = -1, done[i] = 0, is[i] = 0;E = 0;ans = -INF;}void add(int u, int v, int w) {W[E] = w, to[E] = v, next[E] = head[u], head[u] = E++;W[E] = w, to[E] = u, next[E] = head[v], head[v] = E++;}void gao(int u, int fa) {sub[tot] = u;int t = tot++;int omax = 0;for (int i = head[u]; i != -1; i = next[i]) {int v = to[i];if (!done[v] && v != fa) {gao(v, u);omax = max(omax, size[v]);}}size[u] = tot - t;if (size[u] > 1)d[u] = omax;}int center(int u) {tot = 0;gao(u, 0);if (tot == 1) return u;int key = N;int res;for (int k = 0; k < tot; k++) {int v = sub[k];d[v] = max(tot - size[v], d[v]);if (size[v] > 1 && d[v] < key) {key = d[v];res = v;}}return res;}void dfs(int u, int fa, int cnt, int sum) {if (cnt > K) return;if (fa) {if (dp2[cnt] == -INF || dp2[cnt] < sum){if (dp2[cnt] == -INF) vec.push_back(cnt);dp2[cnt] = sum;}}for (int i = head[u]; i != -1; i = next[i]) {int v = to[i];if (v != fa && !done[v]) {dfs(v, u, cnt + is[v], sum + W[i]);}}if (fa == root) {if (u != to[head[root]]) {for (int i = 0; i < vec.size(); i++) {int t = vec[i];if (K - is[root] - t >= 0)ans = max(ans, T.op2(0, K - is[root] - t) + dp2[t]);}}for (int i = 0; i < vec.size(); i++) {int t = vec[i];if (dp2[t] > dp1[t]) {dp1[t] = dp2[t];T.op1(t, dp1[t]);}dp2[t] = -INF;}vec.clear();}}void solve(int u) {root = center(u);if (tot == 1) {done[u] = 1;return;}fill(dp1, dp1 + tot + 1, -INF);fill(dp2, dp2 + tot + 1, -INF);T.init(tot);tdfn = 0;dfs(root, 0, 0, 0);for (int i = 0; i <= tot; i++)if (i + is[root] <= K)ans = max(ans, dp1[i]);done[root] = 1;for (int i = head[root]; i != -1; i = next[i])if (!done[to[i]])solve(to[i]);}int main() {/*int SIZE = 256 << 20; // 256MBchar *p = (char*)malloc(SIZE) + SIZE;__asm__("movl %0, %%esp\n" :: "r"(p) );*/int m, u, v, w, t;n = readint(), K = readint(), m = readint();init();for (int i = 0; i < m; i++) {t = readint();is[t] = 1;}for (int i = 0; i < n - 1; i++) {u = readint();v = readint();scanf("%d", &w);add(u, v, w);}solve(1);for (int i = 1; i <= n; i++)if (is[i] <= K && ans < 0) {ans = 0;break;}printf("%d\n", ans);return 0;}