HDU 4366 Successor(dfs序 + 分块)题解

题意:每个人都有一个上司,每个人都有能力值和忠诚值,0是老板,现在给出m个询问,每次询问给出一个x,要求你找到x的所有直系和非直系下属中能力比他高的最忠诚的人是谁

思路:因为树上查询很麻烦,所以我们直接dfs序把关系变成线性。然后我们再分块,把每个块按照能力值升序排列,这样我们就能直接二分查找这个块内能力值大于x的数就是二分出来的数到块末尾的所有数。但是怎么查找最忠诚的?我们直接预处理每个块内i位置到块末尾的最忠诚人的位置就行了。

代码:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 50000 + 10;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct node{
    int name, loyalty, ability;
    bool operator < (const node &x) const{
        return ability < x.ability;
    }
}p[maxn];
int loyalty[maxn], ability[maxn];
int in[maxn], out[maxn];    //在dfs序列中的位置1-id
int belong[maxn], id;
int head[maxn], tot;
struct Edge{
    int to, next;
}edge[maxn];
void init(){
    tot = id = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v){
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void dfs(int u){
    in[u] = ++id;
    p[id].ability = ability[u], p[id].loyalty = loyalty[u], p[id].name = u;
    for(int i = head[u]; i != -1; i = edge[i].next){
        int v = edge[i].to;
        dfs(v);
    }
    out[u] = id;
}
int MaxLoy[maxn];    //从位置j到所属块末尾的最大loyalty的人在dfs序列的位置
int n, m, block, sz;
int solve(int x){
    int l = belong[in[x]], r = belong[out[x]];
    int L, R;
    int MaxLoyalty = -1, ans = -1;

    L = block * (l - 1) + 1, R = min(L + block - 1, id);
    for(int i = L; i <= R; i++){
        if(in[p[i].name] > in[x] && out[p[i].name] <= out[x]){
            if(p[i].loyalty > MaxLoyalty && p[i].ability > ability[x]){
                MaxLoyalty = p[i].loyalty;
                ans = p[i].name;
            }
        }
    }
    L = l + 1, R = r - 1;
    node c;
    c.ability = ability[x];
    for(int i = L; i <= R; i++){
        int s = block * (i - 1) + 1, e = s + block;
        int pos = upper_bound(p + s, p + e, c) - p;
        if(pos >= e) continue;
        int tmp = MaxLoy[pos];
        if(p[tmp].loyalty > MaxLoyalty){
            MaxLoyalty = p[tmp].loyalty;
            ans = p[tmp].name;
        }
    }
    L = block * (r - 1) + 1, R = min(L + block - 1, id);
    for(int i = L; i <= R; i++){
        if(in[p[i].name] > in[x] && out[p[i].name] <= out[x]){
            if(p[i].loyalty > MaxLoyalty && p[i].ability > ability[x]){
                MaxLoyalty = p[i].loyalty;
                ans = p[i].name;
            }
        }
    }
    return ans;
}
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        init();
        int a;
        scanf("%d%d", &n, &m);
        ability[0] = -1, loyalty[0] = -1;
        for(int i = 1; i <= n - 1; i++){
            scanf("%d%d%d", &a, &loyalty[i], &ability[i]);
            addEdge(a, i);
        }
        dfs(0);
        block = (int)sqrt(id * 1.0);
        for(int i = 1; i <= id; i++){
            belong[i] = (i - 1) / block + 1;
        }
        sz = belong[id];
        for(int i = 1; i <= sz; i++){
            int s = block * (i - 1) + 1, e = min(s + block, id + 1);
            sort(p + s, p + e);
            int Max = -1, pos;
            for(int j = e - 1; j >= s; j--){
                if(Max < p[j].loyalty){
                    Max = p[j].loyalty;
                    pos = j;
                }
                MaxLoy[j] = pos;
            }
        }
        while(m--){
            scanf("%d", &a);
            printf("%d\n", solve(a));
        }
    }
    return 0;
}

 

posted @ 2019-03-20 19:42  KirinSB  阅读(318)  评论(0编辑  收藏  举报