首页 > 代码库 > 树链剖分处理+线段树解决问题 HDU 5029

树链剖分处理+线段树解决问题 HDU 5029

http://acm.split.hdu.edu.cn/showproblem.php?pid=5029

 

题意:n个点的树,m次操作。每次操作输入L,R,V,表示在[L,R]这个区间加上V这个数字。比如[1,2]加上1,[1,3]加上1,那么1这个点就是{1,1},2也是{1,1},3是{1}。全部操作操作完之后,输出每个点中,最多的那个数字有几个。如果有相同的数字,就输出最小的那个数。比如{1,1,2,2},就输出1。

 

思路:树链剖分拍成链,然后通过找LCA,来离线预处理,然后最后通过离线暴力一遍线段树,来完成询问操作(md,add这个函数错了4个小时TAT)

技术分享
//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 1e5 + 5;
int belong[maxn], pos[maxn], son[maxn], id[maxn];
int par[maxn], sz[maxn], deep[maxn], ans[maxn];
int n, m, dfstime;
vector<int> G[maxn];
vector<pair<int, int> > color[maxn];
int tree[maxn << 2];

void init(){
    for (int i = 1; i <= n; i++) G[i].clear();
    for (int i = 1; i <= 100000; i++) color[i].clear();
    memset(belong, 0, sizeof(belong));
    memset(son, 0, sizeof(son));
    memset(par, 0, sizeof(par));
    memset(deep, 0, sizeof(deep));
    memset(sz, 0, sizeof(sz));
    for (int i = 1; i < n; i++){
        int u, v; scanf("%d%d", &u, &v);
        G[u].pb(v), G[v].pb(u);
    }
}

void dfs_size(int u, int fa, int road){
    deep[u] = road, par[u] = fa;
    sz[u] = 1;
    for (int i = 0; i < G[u].size(); i++){
        int v = G[u][i];
        if (v == fa) continue;
        dfs_size(v, u, road + 1);
        sz[u] += sz[v];
        if (sz[v] > sz[son[u]]) son[u] = v;
    }
}

void dfs_tree(int u, int fa, int chain){
    pos[u] = ++dfstime; belong[u] = chain; id[dfstime] = u;
    if (son[u] == 0) return ;
    dfs_tree(son[u], u, chain);
    for (int i = 0; i < G[u].size(); i++){
        int v = G[u][i];
        if (v == fa || v == son[u]) continue;
        dfs_tree(v, u, v);
    }
}

void add(int x, int y, int c){///加入边
    while (belong[x] != belong[y]){
        if (deep[belong[x]] < deep[belong[y]]) swap(x, y);
        color[pos[belong[x]]].push_back(mk(c, 1));
        color[pos[x] + 1].push_back(mk(c, -1));
        x = par[belong[x]];
    }
    if (deep[x] < deep[y]) swap(x, y);
    color[pos[y]].push_back(mk(c, 1)), color[pos[x] + 1].push_back(mk(c, -1));
}

void update(int p, int l, int r, int o, int val){
    if (p == l && p == r){
        tree[o] += val; return ;
    }
    int mid = (l + r) / 2, lb = o << 1, rb = o << 1 | 1;
    if (p <= mid) update(p, l, mid, lb, val);
    if (p > mid) update(p, mid + 1, r, rb, val);
    tree[o] = max(tree[lb], tree[rb]);
}

int query(int l, int r, int o){
    if (l == r) {
        if (tree[o] == 0) return 0;
        return l;
    }
    int mid = (l + r) / 2, lb = o << 1 , rb = o << 1 | 1;
    if (tree[lb] >= tree[rb]) return query(l, mid, lb);
    else return query(mid + 1, r, rb);
}

int main(){
    while (scanf("%d%d", &n, &m) == 2){
        if (n == 0 && m == 0) break;
        init(); dfstime = 0;
        dfs_size(1, 0, 1);
        dfs_tree(1, 0, 1);
        for (int i = 1; i <= m; i++){
            int x, y, z; scanf("%d%d%d", &x, &y, &z);
            add(x, y, z);
        }
        memset(tree, 0, sizeof(tree));
        for (int i = 1; i <= n; i++){
            for (int j = 0; j < color[i].size(); j++){
                int c = color[i][j].first, val = color[i][j].second;
                update(c, 1, 100000, 1, val);
            }
            ans[id[i]] = query(1, 100000, 1);
        }
        for (int i = 1; i <= n; i++){
            printf("%d\n", ans[i]);
        }
    }
    return 0;
}
View Code

 

树链剖分处理+线段树解决问题 HDU 5029