[BZOJ3307] 雨天的尾巴
Description
N个点,形成一个树状结构。有M次发放,每次选择两个点x,y
对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成
所有发放后,每个点存放最多的是哪种物品。
Input
第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题
Output
输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有
多种物品的数量一样,输出编号最小的。如果某个点没有物品
则输出0
Sample Input
20 50
8 6
10 6
18 6
20 10
7 20
2 18
19 8
1 6
14 20
16 10
13 19
3 14
17 18
11 19
4 11
15 14
5 18
9 10
12 15
11 14 87
12 1 87
14 3 84
17 2 36
6 5 93
17 6 87
10 14 93
5 16 78
6 15 93
15 5 16
11 8 50
17 19 50
5 4 87
15 20 78
1 17 50
20 13 87
7 15 22
16 11 94
19 8 87
18 3 93
13 13 87
2 1 87
2 6 22
5 20 84
10 12 93
18 12 87
16 10 93
8 17 93
14 7 36
7 4 22
5 9 87
13 10 16
20 11 50
9 16 84
10 17 16
19 6 87
12 2 36
20 9 94
9 2 84
14 1 94
5 5 94
8 17 16
12 8 36
20 17 78
12 18 50
16 8 94
2 19 36
10 18 36
14 19 50
4 12 50
8 6
10 6
18 6
20 10
7 20
2 18
19 8
1 6
14 20
16 10
13 19
3 14
17 18
11 19
4 11
15 14
5 18
9 10
12 15
11 14 87
12 1 87
14 3 84
17 2 36
6 5 93
17 6 87
10 14 93
5 16 78
6 15 93
15 5 16
11 8 50
17 19 50
5 4 87
15 20 78
1 17 50
20 13 87
7 15 22
16 11 94
19 8 87
18 3 93
13 13 87
2 1 87
2 6 22
5 20 84
10 12 93
18 12 87
16 10 93
8 17 93
14 7 36
7 4 22
5 9 87
13 10 16
20 11 50
9 16 84
10 17 16
19 6 87
12 2 36
20 9 94
9 2 84
14 1 94
5 5 94
8 17 16
12 8 36
20 17 78
12 18 50
16 8 94
2 19 36
10 18 36
14 19 50
4 12 50
Sample Output
87
36
84
22
87
87
22
50
84
87
50
36
87
93
36
94
16
87
50
50
1<=N,M<=100000
1<=a,b,x,y<=N
1<=z<=10^9
在树上的每个点开一棵权值线段树, 并且维护区间最大值的大小。
对一条路径(x,y)进行操作,可以转化为在x点+1,在y点加1,在lca处减1,在lca的父亲那减一。
然后dfs一遍线段树合并,线段树上二分查询答案。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; #define reg register inline int read() { int res = 0;char ch=getchar();bool fu=0; while(!isdigit(ch)) {if(ch=='-')fu=1;ch=getchar();} while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48), ch=getchar(); return fu?-res:res; } #define N 100005 int n, m; struct edge { int nxt, to; }ed[N*2]; int head[N], cnt; inline void add(int x, int y) { ed[++cnt] = (edge){head[x], y}; head[x] = cnt; } int Fa[N][20], dep[N]; inline void bfs() { dep[0] = -1, dep[1] = 1; queue <int> q; q.push(1); while(!q.empty()) { int x = q.front();q.pop(); for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (dep[to]) continue; dep[to] = dep[x] + 1; Fa[to][0] = x; q.push(to); for (reg int j = 1 ; j <= 19 ; j ++) Fa[to][j] = Fa[Fa[to][j-1]][j-1]; } } } inline int lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); for (reg int i = 19 ; i >= 0 ; i --) if (dep[Fa[x][i]] >= dep[y]) x = Fa[x][i]; if (x == y) return x; for (reg int i = 19 ; i >= 0 ; i --) if (Fa[x][i] != Fa[y][i]) x = Fa[x][i], y = Fa[y][i]; return Fa[x][0]; } int root[N]; int tr[N*100], ls[N*100], rs[N*100], tot; inline void pushup(int o) { tr[o] = max(tr[ls[o]], tr[rs[o]]); } int Insert(int l, int r, int o, int p, int d) { if (!o) o = ++tot; if (l == r) { tr[o] += d; return o; } int mid = l + r >> 1; if (p <= mid) ls[o] = Insert(l, mid, ls[o], p, d); else rs[o] = Insert(mid + 1, r, rs[o], p, d); pushup(o); return o; } int Merge(int l, int r, int a, int b) { if (a * b == 0) return a + b; int jd = ++tot; if (l == r) { tr[jd] = tr[b] + tr[a]; return jd; } int mid = l + r >> 1; ls[jd] = Merge(l, mid, ls[a], ls[b]); rs[jd] = Merge(mid + 1, r, rs[a], rs[b]); pushup(jd); return jd; } void dfs(int x, int fa) { for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (to == fa) continue; dfs(to, x); root[x] = Merge(1, 100000, root[x], root[to]); } } int query(int l, int r, int o) { if (l == r) return l; if (!tr[o]) return 0; int mid = l + r >> 1; if (tr[ls[o]] >= tr[rs[o]]) return query(l, mid, ls[o]); else return query(mid + 1, r, rs[o]); } int main() { n = read(), m = read(); for (reg int i = 1 ; i < n ; i ++) { int x = read(), y = read(); add(x, y), add(y, x); } bfs(); for (reg int i = 1 ; i <= m ; i ++) { int x = read(), y = read(), z = read(); int l = lca(x, y); root[x] = Insert(1, 100000, root[x], z, 1); root[y] = Insert(1, 100000, root[y], z, 1); root[l] = Insert(1, 100000, root[l], z, -1); root[Fa[l][0]] = Insert(1, 100000, root[Fa[l][0]], z, -1); } dfs(1, 0); for (reg int i = 1 ; i <= n ; i ++) printf("%d\n", query(1, 100000, root[i])); return 0; }