zoukankan      html  css  js  c++  java
  • [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
    ", query(1, 100000, root[i]));
        return 0;
    }
  • 相关阅读:
    女孩提出分手的N种理由
    Attribute应用,简化ANF自定义控件初始化过程
    关于Web的动态页面与静态页面分开的想法.
    .Net面试题
    算法题,不用递归,构造树型
    花两个小时,做了个分页控件
    事件应用,为系统提供扩展功能
    绘制半透明的图片
    Tile Studio简介(转载)
    Thinking in Java 摘录笔记
  • 原文地址:https://www.cnblogs.com/BriMon/p/9638426.html
Copyright © 2011-2022 走看看