线段树合并

#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;
const int MAXN = 1e5 + 5;

int n, m;
struct Edge {
    int to, next;
} edge[MAXN * 2];
int start[MAXN], fth[MAXN];
struct LCA {
    int x, y, z, val;
} lca[MAXN];
struct Query_LCA {
    int to, id;
};
vector<Query_LCA> query_lca[MAXN];
int djs[MAXN];
bool vis[MAXN];

int Find(int x) {
    if (x == djs[x])return x;
    return djs[x] = Find(djs[x]);
}

void Tarjan(int p) {
    vis[p] = true;
    for (int i = start[p]; i; i = edge[i].next) {
        if (edge[i].to == fth[p])continue;
        fth[edge[i].to] = p;
        Tarjan(edge[i].to);
    }
    for (auto q:query_lca[p])if (vis[q.to])lca[q.id].z = Find(q.to);
    djs[p] = fth[p];
}

vector<int> add[MAXN], ers[MAXN];

struct Weight_Tree {
    int ch[2], val, wch;

    Weight_Tree() {//NOLINT
        ch[0] = ch[1] = val = wch = 0;
    }
} tree[MAXN * 40];//NOLINT
int tot = 0, root[MAXN], ans[MAXN];
int recycle[MAXN * 40], cnt = 0;//NOLINT

int Build() {
    if (cnt == 0)return ++tot;
    return recycle[cnt--];
}

void Insert(int p, int l, int r, int x, int y) {
    if (l == r) {
        tree[p].val += y;
        tree[p].wch = tree[p].val > 0 ? l : 0;
        return;
    }
    int mid = (l + r) / 2;
    if (l <= x && x <= mid) {
        if (tree[p].ch[0] == 0)tree[p].ch[0] = Build();
        Insert(tree[p].ch[0], l, mid, x, y);
    }
    if (mid + 1 <= x && x <= r) {
        if (tree[p].ch[1] == 0)tree[p].ch[1] = Build();
        Insert(tree[p].ch[1], mid + 1, r, x, y);
    }
    tree[p].val = max(tree[tree[p].ch[0]].val, tree[tree[p].ch[1]].val);
    tree[p].wch = tree[tree[p].ch[0]].val >= tree[tree[p].ch[1]].val ?
                  tree[tree[p].ch[0]].wch : tree[tree[p].ch[1]].wch;
}

int Merge(int p, int q, int l, int r) {
    if (p == 0 || q == 0)return p + q;
    if (l == r) {
        tree[p].val += tree[q].val;
        tree[p].wch = tree[p].val > 0 ? l : 0;
        tree[q].ch[0] = tree[q].ch[1] = tree[q].val = tree[q].wch = 0;
        recycle[++cnt] = q;
        return p;
    }
    int mid = (l + r) / 2;
    tree[p].ch[0] = Merge(tree[p].ch[0], tree[q].ch[0], l, mid);
    tree[p].ch[1] = Merge(tree[p].ch[1], tree[q].ch[1], mid + 1, r);
    tree[q].ch[0] = tree[q].ch[1] = tree[q].val = tree[q].wch = 0;
    recycle[++cnt] = q;
    tree[p].val = max(tree[tree[p].ch[0]].val, tree[tree[p].ch[1]].val);
    tree[p].wch = tree[tree[p].ch[0]].val >= tree[tree[p].ch[1]].val ?
                  tree[tree[p].ch[0]].wch : tree[tree[p].ch[1]].wch;
    return p;
}

void dfs(int p) {
    root[p] = Build();
    for (int i = start[p]; i; i = edge[i].next) {
        if (edge[i].to == fth[p])continue;
        dfs(edge[i].to);
        root[p] = Merge(root[p], root[edge[i].to], 1, 1e5);
    }
    for (auto k:add[p])Insert(root[p], 1, 1e5, k, 1);
    for (auto k:ers[p])Insert(root[p], 1, 1e5, k, -1);
    ans[p] = tree[root[p]].wch;
}

signed main() {
    scanf("%d %d", &n, &m);//NOLINT
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d %d", &u, &v);//NOLINT
        edge[2 * i - 1] = {v, start[u]};
        start[u] = 2 * i - 1;
        edge[2 * i] = {u, start[v]};
        start[v] = 2 * i;
    }
    for (int i = 1; i <= m; i++) {
        scanf("%d %d %d", &lca[i].x, &lca[i].y, &lca[i].val);//NOLINT
        query_lca[lca[i].x].push_back({lca[i].y, i});
        query_lca[lca[i].y].push_back({lca[i].x, i});
    }
    for (int i = 1; i <= n; i++)djs[i] = i;
    Tarjan(1);
    for (int i = 1; i <= m; i++) {
        add[lca[i].x].push_back(lca[i].val);
        add[lca[i].y].push_back(lca[i].val);
        ers[lca[i].z].push_back(lca[i].val);
        ers[fth[lca[i].z]].push_back(lca[i].val);
    }
    dfs(1);
    for (int i = 1; i <= n; i++)printf("%d\n", ans[i]);
    printf("%d\n", tot);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值