[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

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;
}

猜你喜欢

转载自www.cnblogs.com/BriMon/p/9638426.html
今日推荐