您的位置:首页 > 其它

BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )

2016-02-17 12:16 666 查看


路径(x, y) +z : u处+z, v处+z, lca(u,v)处-z, fa(lca)处-z, 然后dfs一遍, 用线段树合并. O(M log M + M log N). 复杂度看起来不高, 但是跑起来很慢.

另一种做法是先树链剖分, 转成序列上的情况, 然后依旧是差分+线段树维护, O(M log N log M). 但是实际跑起来好像更快...

------------------------------------------------------------------------------

#include<cstdio>

#include<cctype>#include<cstring>#include<algorithm> using namespace std; const int maxn = 100009; int N, M;int Hash[maxn], Hn; template<class T>inline void Min(T &x, T t) { if(t < x) x = t;}template<class T>inline void Max(T &x, T t) { if(t > x) x = t;} inline int getint() { char c = getchar(); for(; !isdigit(c); c = getchar()); int ret = 0; for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0'; return ret;} struct L {

int x; L* n;} Lpool[maxn * 4], *Pt = Lpool, *Head[maxn]; inline void AddL(int a, int b) { Pt->x = b, Pt->n = Head[a], Head[a] = Pt++;} struct O { int x, y, z;} o[maxn]; struct edge { int t; edge* n;} E[maxn << 1], *ept = E, *H[maxn]; inline void AddEdge(int u, int v) { ept->t = v, ept->n = H[u], H[u] = ept++;} void Init() { Hn = 0; int u, v; N = getint(), M = getint(); for(int i = 1; i < N; i++) { u = getint() - 1, v = getint() - 1; AddEdge(u, v); AddEdge(v, u); } for(int i = 0; i < M; i++) { o[i].x = getint() - 1; o[i].y = getint() - 1; Hash[Hn++] = o[i].z = getint(); } Hash[Hn++] = 0; sort(Hash, Hash + Hn); Hn = unique(Hash, Hash + Hn) - Hash; for(int i = 0; i < M; i++) o[i].z = lower_bound(Hash, Hash + Hn, o[i].z) - Hash;} int top[maxn], sz[maxn], ch[maxn], fa[maxn], dep[maxn];int Top; void dfs(int x) { sz[x] = 1, ch[x] = -1; for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x]) { dep[e->t] = dep[x] + 1; fa[e->t] = x; dfs(e->t); sz[x] += sz[e->t]; if(!~ch[x] || sz[ch[x]] < sz[e->t]) ch[x] = e->t; }} void DFS(int x) { top[x] = Top; if(~ch[x]) DFS(ch[x]); for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x] && e->t != ch[x]) DFS(Top = e->t);} int LCA(int x, int y) { for(; top[x] != top[y]; x = fa[top[x]]) if(dep[top[x]] < dep[top[y]]) swap(x, y); return dep[x] < dep[y] ? x : y;} struct Node { Node *lc, *rc; int mx, Id; inline void upd() { mx = -maxn, Id = maxn; if(lc) Max(mx, lc->mx); if(rc) Max(mx, rc->mx); if(lc && lc->mx == mx) Min(Id, lc->Id); if(rc && rc->mx == mx) Min(Id, rc->Id); }} pool[maxn * 70], *pt = pool, *V[maxn]; int Val, Pos; void Modify(Node*&t, int l, int r) { if(!t) (t = pt++)->mx = 0; int m = (l + r) >> 1; if(l == r) { t->mx += Val; t->Id = m; } else { Pos <= m ? Modify(t->lc, l, m) : Modify(t->rc, m + 1, r); t->upd(); } if(!t->mx) t = 0;} Node* Merge(Node* a, Node* b, int l, int r) { int m = (l + r) >> 1; if(!a) return b; if(!b) return a; if(l != r) { a->lc = Merge(a->lc, b->lc, l, m); a->rc = Merge(a->rc, b->rc, m + 1, r); a->upd(); } else a->mx += b->mx; return a;} int ans[maxn]; void calc(int x) { for(L* t = Head[x]; t; t = t->n) { if(t->x > 0) Pos = t->x, Val = 1; else Pos = -t->x, Val = -1; Modify(V[x], 1, Hn); } for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x]) { calc(e->t); V[x] = Merge(V[x], V[e->t], 1, Hn); } ans[x] = V[x] ? V[x]->Id : 0;} void Work() { fa[0] = -1; dep[0] = 0; dfs(0); DFS(Top = 0); for(int i = 0; i < M; i++) { int lca = LCA(o[i].x, o[i].y); AddL(o[i].x, o[i].z); AddL(o[i].y, o[i].z); AddL(lca, -o[i].z); if(~fa[lca]) AddL(fa[lca], -o[i].z); } calc(0); for(int i = 0; i < N; i++) printf("%d\n", Hash[ans[i]]);} int main() {

Init(); Work(); return 0;}------------------------------------------------------------------------------

3307: 雨天的尾巴

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 267 Solved: 127
[Submit][Status][Discuss]

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

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

HINT

Source

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: