HDU 4366 Successor (线段树)

原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=4366

题意: 给你一棵树,每个结点有两个属性值,1:能力值   2:忠诚度

然后m个询问,每次询问一个整数u,求u的子树中能力值大于u的且忠诚度最大的点的编号

思路:首先如果不考虑能力值的要求,只考虑求忠诚度的要求,然后又因为这是在树上的,所以我们可以将树进行DFS转化为DFS序,这样之后就是求在某一区间上的区间最值,,很明显这是可利用线段树去做的.但是现在的限制谈条件又多了一个.那么我们就考虑将所有的能力值按从大到小排序,这样子,我们每次查询的都是能力比当前大的节点,就满足题目要求了.

#include <bits/stdc++.h>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 5e4 + 5;
const int mod = 998244353;
int t, n, m, cnt;
int ans[maxn];
map<int, int>mp;//因为题目说了忠诚值全都不一样,所以可以映射
vector<int>G[maxn];
void init() {
    cnt = 0;
    CLR(ans, -1);
    mp.clear();
    for (int i = 0; i <= n; i++) G[i].clear();
}
void add_edge(int u, int v) {
    G[u].push_back(v);
}
int st[maxn], en[maxn];
void dfs(int u) {//dfs序
    st[u] = cnt++; //第一次出现
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        dfs(v);
    }
    en[u] = cnt;//记得放外面
}
int id, MAX[maxn << 2]; //MAX能力值
void push_up(int rt) {
    MAX[rt] = max(MAX[rt << 1], MAX[rt << 1 | 1]);
}
void build(int l, int r, int rt) {//建树
    MAX[rt]  = -1;
    if (l == r) {
        return ;
    }
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
    push_up(rt);
}
void updata(int p, int val, int l, int r, int rt) {//单点更新
    if (l == r) {
        MAX[rt] = val;
        return ;
    }
    int mid = (l + r) >> 1;
    if (mid >= p) updata(p, val, lson);
    else updata(p,  val, rson);
    push_up(rt);
}
int query(int L, int R, int l, int r, int rt) { //查询区间最大值
    if (L > R) return -1;
    if (L <= l && R >= r) {
        return MAX[rt];
    }
    int mid = (l + r) >> 1;
    int res = -1;
    if (mid >= L) res = max(res, query(L, R, lson));
    if (mid < R) res = max(res, query(L, R, rson));
    return res;
}
struct info {
    int id, loy, abi;
} e[maxn];
bool cmp(info a, info b) {
    return a.abi > b.abi;
}

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &m);
        init();
        for (int i = 1; i <= n - 1; i++) {
            scanf("%d%d%d", &id, &e[i].loy, &e[i].abi);
            add_edge(id, i);
            e[i].id = i;
            mp[e[i].loy] = i;
        }
        sort(e + 1, e + n, cmp);
        dfs(0);
        build(0, n - 1, 1);
        for (int i = 1, j; i < n; i = j) {
            j = i;
            while (j < n && e[i].abi == e[j].abi) {
                int id = e[j].id;
                int x = query(st[id] + 1, en[id] - 1, 0, n - 1, 1);
                //+1 -1 是因为查询区间是以id为根的子树
                if (x != -1) ans[id] = mp[x];
                j++;
            }
            j = i;
            while (j < n && e[i].abi == e[j].abi) {
                int id = e[j].id;
                updata(st[id], e[j].loy, 0, n - 1, 1);
                j++;
            }
        }
        for (int i = 1; i <= m; i++) {
            int x;
            scanf("%d", &x);
            printf("%d\n",ans[x]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81673746
今日推荐