[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——题解

HDU5446 Unknown Treasure(组合数+Lucas+中国剩余定理)

hdu 5446 Unknown Treasure 卢卡斯+中国剩余定理

HDU 5446 Unknown Treasure(Lucas定理+CRT)

hdu 3642 Get The Treasure

网络流 HDU 3468 Treasure Hunting