树链剖分处理+线段树解决问题 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;
}

时间: 2024-10-22 10:53:31

树链剖分处理+线段树解决问题 HDU 5029的相关文章

HDU - 3966 Aragorn&#39;s Story(树链剖分入门+线段树)

HDU - 3966 Aragorn's Story Time Limit: 3000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of ene

poj 3237 Tree(树链剖分,线段树)

Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with

bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status][Discuss] Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. 有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[

bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit][Status][Discuss] Description 一 棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

bzoj 3531 [Sdoi2014]旅行(树链剖分,线段树)

3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 876  Solved: 446[Submit][Status][Discuss] Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰.为了方便,我们用不同的正整数代表 各种宗教,  S国的居民常常旅行.旅行时他们总

[Bzoj4196] [NOI2015] 软件包管理器 [树链剖分,线段树]

题解摘要:树链剖分后用线段树区间查询修改,对于安装软件,将改点到根的路径全部变为1,对于卸载软件,将子树清空.注意边界,编号是从0开始的,容易漏掉树根. 第一次写树剖- 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 #inclu

ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat (树链剖分-线性变换线段树)

树链剖分若不会的话可自行学习一下. 前两种操作是线性变换,模\(2^{64}\)可将线段树全部用unsigned long long 保存,另其自然溢出. 而取反操作比较不能直接处理,因为其模\(2^{64}\)的特殊性,可将其转化为线性变换. 显然 \[-x\equiv (2^{64}-1)*x (mod\ 2^{64})\] 因为\[!x = (2^{64}-1) -x \] 所以 \[ !x = (2^{64}-1) + (2^{64}-1)x\] #include<bits/stdc++

Luogu2542 AHOI2005 航线规划 树链剖分、线段树

传送门 看到删边不用想就是反着加边 先把删完边之后的图拆一个生成树出来,然后考虑非树边的影响.实际上非树边就是让树上的一条路径的权值从$1$变为了$0$,而每一个询问就是一条路径上的权值之和.使用树链剖分+线段树维护权值即可. 1 #include<bits/stdc++.h> 2 #define lch (now << 1) 3 #define rch (now << 1 | 1) 4 #define mid ((l + r) >> 1) 5 //This

cogs 1583. [POJ 3237] 树的维护 树链剖分套线段树

1583. [POJ 3237] 树的维护 ★★★★   输入文件:maintaintree.in   输出文件:maintaintree.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条边的权值改成v. NEGATE a b:将点a到点b路径上所有边的权值变成其相反数. QUERY a b