洛谷P4556 雨天的尾巴(线段树合并)

洛谷P4556 雨天的尾巴

题目链接

题解:
因为一个点可能存放多种物品,直接开二维数组进行统计时间、空间复杂度都不能承受。因为每一个点所拥有的物品只与其子树中的点有关,所以可以考虑对每一个点来建立一颗权值线段树来维护多种物品以及其数量,然后最后在回溯时合并,这样就可以得到我们所需要的信息了。
因为题目中要求的是哪一种物品,所以我们可以顺带维护一下位置信息,就不用到时候每次去query了。
注意一下,就是当一个点的sum为0时,其pos应该为置为0。
详见代码吧:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n, m;
struct Edge{
    int v, next;
}e[N << 1];
int head[N], tot, D;
void adde(int u, int v) {
    e[tot].v = v; e[tot].next = head[u]; head[u] = tot++;
}
int f[N][22], deep[N] ;
int rt[N], ls[N * 100], rs[N * 100], pos[N * 100], sum[N * 100] ;
int X[N], Y[N], Z[N], b[N], ans[N];
void dfs1(int u, int fa) {
    deep[u] = deep[fa] + 1;
    for(int i = head[u]; i != -1; i = e[i].next){
        int v = e[i].v;
        if(v == fa) continue ;
        f[v][0] = u;
        for(int j = 1; j <= 20; j++) f[v][j] = f[f[v][j - 1]][j - 1] ;
        dfs1(v, u) ;
    }
}
int LCA(int x, int y) {
    if(deep[x] < deep[y]) swap(x, y);
    for(int i = 20; i >= 0; i--) {
        if(deep[f[x][i]] >= deep[y]) x = f[x][i] ;
    }
    if(x == y) return x;
    for(int i = 20; i >= 0; i--) {
        if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i] ;
    }
    return f[x][0] ;
}
void insert(int o, int l, int r, int val, int sign) {
    if(l == r) {
        sum[o] += sign;
        pos[o] = sum[o] > 0 ? l : 0;
        return ;
    }
    int mid = (l + r) >> 1;
    if(val <= mid) {
        if(!ls[o]) ls[o] = ++tot;
        insert(ls[o], l, mid, val, sign) ;
    } else {
        if(!rs[o]) rs[o] = ++tot;
        insert(rs[o], mid + 1, r, val, sign) ;
    }
    sum[o] = max(sum[ls[o]], sum[rs[o]]) ;
    pos[o] = sum[ls[o]] >= sum[rs[o]] ? pos[ls[o]] : pos[rs[o]];
}
int merge(int x, int y, int l, int r) {
    if(!x) return y;
    if(!y) return x;
    if(l == r) {
        sum[x] += sum[y] ;
        pos[x] = sum[x] > 0 ? l : 0;
        return x;
    }
    int mid = (l + r) >> 1;
    ls[x] = merge(ls[x], ls[y], l, mid) ;
    rs[x] = merge(rs[x], rs[y], mid + 1, r) ;
    sum[x] = max(sum[ls[x]], sum[rs[x]]) ;
    pos[x] = sum[ls[x]] >= sum[rs[x]] ? pos[ls[x]] : pos[rs[x]] ;
    return x;
}
void dfs2(int u, int fa) {
    for(int i = head[u]; i != -1; i = e[i].next) {
        int v = e[i].v;
        if(v == fa) continue ;
        dfs2(v, u) ;
        rt[u] = merge(rt[u], rt[v], 1, D) ;
    }
    ans[u] = pos[rt[u]];
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> n >> m;
    memset(head, -1, sizeof(head)) ;
    for(int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        adde(u, v); adde(v, u);
    }
    dfs1(1, 0) ;
    for(int i = 1; i <= n; i++) rt[i] = i;
    tot = n;
    for(int i = 1; i <= m; i++) {
        cin >> X[i] >> Y[i] >> Z[i] ;
        b[i] = Z[i] ;
    }
    sort(b + 1, b + m + 1);
    D = unique(b + 1, b + m + 1) - b - 1;
    for(int i = 1; i <= m; i++) {
        int x = X[i], y = Y[i], z = Z[i] ;
        int k = lower_bound(b + 1, b + D + 1, z) - b;
        int lca = LCA(x, y) ;
        insert(rt[x], 1, D, k, 1) ;
        insert(rt[y], 1, D, k, 1) ;
        insert(rt[lca], 1, D, k, -1) ;
        if(f[lca][0]) insert(rt[f[lca][0]], 1, D, k, -1) ;
    }
    dfs2(1, 0) ;
    for(int i = 1; i <= n; i++) cout << b[ans[i]] << '\n' ;
    return 0;
}

posted @ 2019-05-19 22:33  heyuhhh  阅读(274)  评论(0编辑  收藏  举报