HDU 4366 Successor (dfs序列+分块)

题目

Problem Description
Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty and ability.Some times Sean will fire one staff.Then one of the fired man’s Subordinates will replace him whose ability is higher than him and has the highest loyalty for company.Sean want to know who will replace the fired man.

题解

给你一个棵树,每棵树有两个属性,忠诚度和能力值,给你一个点,在他的子孙节点中找到比他能力值强且最忠诚的一个,顶替他的位置,输出编号。好像一个二维偏序?假设我们已经有了这个点的子孙区间,我们该如何得到这个值,考虑一下分块,朴素的扫法就是两个条件去判断,过程中去极值。那么我们想一下如何维护大段,根据二维偏序的做法,我们只需要在排好序的分块数组里面二分出这个点的位置,然后扫一遍剩余的点,取最大值就可以了,那么这个东西我们在建立分块的时候就可以(O(N))预处理出来,所以我们只需要在每个大段里面二分位置就可以了,左右区间朴素扫。子孙区间的话,维护个dfs序就好了。ps:lower_bound和upper_bound是走闭右开,R!N!M!

Code

#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 L[maxn],R[maxn];
int loyalty[maxn], ability[maxn];
int in[maxn],out[maxn];    //在dfs序列中的位置1-id
int belong[maxn], id;
int head[maxn], tot;

int st[maxn],to[maxn],nt[maxn],topt;
void init(){
    topt=id=0;
    memset(st,0,sizeof(st));
}

void add_edge (int u,int v) {
    to[++topt]=v;
    nt[topt]=st[u];
    st[u]=topt;
}
void dfs(int u){
    in[u]=++id;
    p[id].ability=ability[u],p[id].loyalty=loyalty[u],p[id].name=u;
    int now=st[u];
    while (now) {
        dfs (to[now]);
        now=nt[now];
    }
    out[u]=id;
}
int MaxLoy[maxn];    
int n,m,block,sz;
int solve(int x){
    int l=belong[in[x]], r=belong[out[x]];
    int a,b;
    int MaxLoyalty=-1, ans=-1;

    a=L[l],b=R[l];
    for(int i=a;i<=b;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;
            }
        }
    }
    a=l+1,b=r-1;
    node c;
    c.ability=ability[x];
    for(int i=a;i<=b; 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;
        }
    }

    a=L[r],b=R[r];
    for(int i=a;i<=b;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;
}

void build () {
    block=sqrt (id);
    int num=id/block; if (id%block) num++;
    for (int i=1;i<=num;i++)  L[i]=(i-1)*block+1,R[i]=i*block;
    R[num]=id;
    for (int i=1;i<=id;i++) belong[i]=(i-1)/block+1;
    for (int i=1;i<=num;i++) {
        int s=L[i],e=min (R[i]+1,id);
        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;
        }
    }
}

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]);
            add_edge(a, i);
        }
        dfs(0);
        build ();
        while(m--) {
            scanf("%d", &a);
            printf("%d
", solve(a));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hhlya/p/14082251.html