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

路径(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

 

posted @ 2016-02-17 12:16  JSZX11556  阅读(444)  评论(0编辑  收藏  举报