[HDU 5770] Treasure
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HDU 5770] Treasure相关的知识,希望对你有一定的参考价值。
题意
给定一棵 n 个节点的树.
有 m 个宝藏, 每个宝藏用 (x, y, w) 刻画, 表示开启宝藏的钥匙在 x , 宝藏的位置在 y , 得到宝藏可以获得价值 w (w 可能为负数).
你打算从树上的每一个节点开始, 访问到另一个节点, 路径上所有的钥匙和宝藏都必须拿, 问最多能获得多少价值.
n <= 100000, m <= 100000.
分析
考虑数形结合.
我们考虑把一条路径 (x, y) , 看做二维平面的一个点 (In[x], In[y]) .
某个宝藏对应在若干个矩形内能取到.
具体地, 我们需要对宝藏 (x, y, w) 分情况讨论.
1. 当 x 不是 y 的祖先, y 不是 x 的祖先, 且 x 与 y 不重合的时候, 对应矩形 ( In[x] ~ Out[x] , In[y] ~ Out[y] ) .
2. 当 x 是 y 的祖先时, 求出 y 在 x 的后继 t 的子树中, 对应矩形 (1 ~ In[t]-1 , In[y] ~ Out[y]) 和 (Out[t]+1 ~ n , In[y] ~ Out[y]) .
3. 当 y 是 x 的祖先时, 类似.
4. 当 x 和 y 重合时, 直接处理的复杂度是 O(n) 的, 要换一种想法.
我们考虑先将答案加上 w , 对于每个被当前点划分出的连通块对应的矩形, 减去 w .
细节: 对于某个点 x , 以 x 为根的子树外, 需要构建 4 个矩形, 而不是 2 个.
实现
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <algorithm> 6 #include <vector> 7 using namespace std; 8 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 9 10 namespace Input { 11 const int S = 2000000; 12 char s[S], *h = s+S, *t = h; 13 inline char getchr(void) { if (h == t) fread(s, 1, S, stdin), h = s; return *h++; } 14 inline int rd(void) { 15 int f = 1; char c = getchr(); for (; !isdigit(c); c = getchr()) if (c == ‘-‘) f = -1; 16 int x = 0; for (; isdigit(c); c = getchr()) x = x*10+c-‘0‘; return x*f; 17 } 18 } 19 using Input::rd; 20 21 const int N = 100005; // 100005 22 const int S = 300000; // 300000 // 262144 23 const int INF = ~0u>>2; 24 25 int n, m; vector<int> g[N]; 26 inline void Init(int x, int y) { g[x].push_back(y), g[y].push_back(x); } 27 28 int son[N], siz[N], par[N], dep[N]; 29 int idx, In[N], Out[N], r[N], top[N]; 30 31 void Son(int x) { 32 siz[x] = 1; 33 for (vector<int>::iterator it = g[x].begin(); it != g[x].end(); it++) 34 if (par[x] != *it) { 35 par[*it] = x, dep[*it] = dep[x]+1; 36 Son(*it); 37 siz[x] += siz[*it]; 38 if (siz[son[x]] < siz[*it]) son[x] = *it; 39 } 40 } 41 void Split(int x, int anc) { 42 In[x] = ++idx, r[idx] = x, top[x] = anc; 43 if (son[x] > 0) Split(son[x], anc); 44 for (vector<int>::iterator it = g[x].begin(); it != g[x].end(); it++) 45 if (par[x] != *it && *it != son[x]) 46 Split(*it, *it); 47 Out[x] = idx; 48 } 49 50 inline int LCA(int x, int y) { 51 while (top[x] != top[y]) 52 dep[top[x]] > dep[top[y]] ? x = par[top[x]] : y = par[top[y]]; 53 return dep[x] < dep[y] ? x : y; 54 } 55 inline int Skip(int x, int cnt) { 56 // cnt <= dep[x] 57 while (true) 58 if (cnt <= dep[x] - dep[top[x]]) 59 return r[In[x] - cnt]; 60 else { 61 cnt = cnt - (dep[x] - dep[top[x]]) - 1; 62 x = par[top[x]]; 63 } 64 } 65 66 int Sg[N], res, D; 67 struct Mat { int L, R, w; }; vector<Mat> List[N]; // n+1 68 inline void Add(int xL, int xR, int yL, int yR, int w) { 69 List[xL].push_back((Mat){yL, yR, +w}); 70 List[xR+1].push_back((Mat){yL, yR, -w}); 71 } 72 73 #define LC (x<<1) 74 #define RC (x<<1|1) 75 #define M ((L+R)>>1) 76 int Max[S], tag[S]; 77 inline void Down(int x, int w) { Max[x] += w, tag[x] += w; } 78 inline void Clear(int x) { if (tag[x] != 0) Down(LC, tag[x]), Down(RC, tag[x]), tag[x] = 0; } 79 inline void Modi(int x, int L, int R, int mL, int mR, int w) { 80 if (mL <= L && R <= mR) { Down(x, w); return; } 81 Clear(x); 82 if (mL <= M) Modi(LC, L, M, mL, mR, w); 83 if (M < mR) Modi(RC, M+1, R, mL, mR, w); 84 Max[x] = max(Max[x<<1], Max[x<<1|1]); 85 } 86 87 int main(void) { 88 #ifndef ONLINE_JUDGE 89 freopen("treasure.in", "r", stdin); 90 #endif 91 92 n = rd(), m = rd(); 93 F(i, 1, n-1) { 94 int x = rd(), y = rd(); 95 Init(x, y); 96 } 97 98 Son(1); 99 Split(1, 1); 100 101 F(i, 1, m) { 102 int x = rd(), y = rd(), w = rd(); 103 if (x == y) Sg[x] += w, D += w; 104 else if (In[x] <= In[y] && Out[y] <= Out[x]) { 105 int t = Skip(y, dep[y] - dep[x] - 1); 106 if (In[t] > 1) Add(1, In[t]-1, In[y], Out[y], w); 107 if (Out[t] < n) Add(Out[t]+1, n, In[y], Out[y], w); 108 } 109 else if (In[y] <= In[x] && Out[x] <= Out[y]) { 110 int t = Skip(x, dep[x] - dep[y] - 1); 111 if (In[t] > 1) Add(In[x], Out[x], 1, In[t]-1, w); 112 if (Out[t] < n) Add(In[x], Out[x], Out[t]+1, n, w); 113 } 114 else Add(In[x], Out[x], In[y], Out[y], w); 115 } 116 F(x, 1, n) if (Sg[x] != 0) 117 for (vector<int>::iterator it = g[x].begin(); it != g[x].end(); it++) 118 if (par[x] == *it) { 119 if (In[x] > 1) Add(1, In[x]-1, 1, In[x]-1, -Sg[x]); 120 if (Out[x] < n) Add(Out[x]+1, n, Out[x]+1, n, -Sg[x]); 121 if (In[x] > 1 && Out[x] < n) { 122 Add(1, In[x]-1, Out[x]+1, n, -Sg[x]); 123 Add(Out[x]+1, n, 1, In[x]-1, -Sg[x]); 124 } 125 } 126 else Add(In[*it], Out[*it], In[*it], Out[*it], -Sg[x]); 127 128 res = -INF; 129 F(x, 1, n) { 130 for (vector<Mat>::iterator it = List[x].begin(); it != List[x].end(); it++) 131 Modi(1, 1, n, it->L, it->R, it->w); 132 res = max(res, Max[1]); 133 } 134 printf("%d\n", res + D); 135 136 return 0; 137 }
以上是关于[HDU 5770] Treasure的主要内容,如果未能解决你的问题,请参考以下文章
HDU5446 Unknown Treasure(组合数+Lucas+中国剩余定理)
hdu 5446 Unknown Treasure 卢卡斯+中国剩余定理