【分块】 HDU 4336 Successor

通道

题意:给一个树,树上每个节点都有两个属性:忠诚度和能力,给出若干查询,求每个子树中能力 > 树根能力的点中,忠诚度最高的那个

思路:子树dfs序即可,然后忠诚度排个序,取能力值大于u且忠诚度最高的,虽然线段树也可以搞,练练分块。

代码:

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <vector>
#include <map>
#include <cstring>
#include <algorithm>
 
using namespace std;

typedef long long Long;

const int MAGIC = 250;
const int MAX_N = 50007;
 
struct staff {
    int loyalty, ability;
};
 
bool operator < (staff a,staff b) {
    return a.ability < b.ability;
}
 
vector<int> adj[MAX_N];
staff arr[MAX_N], list[MAX_N], sorted[MAX_N];
int pos[MAX_N], maxl[MAX_N], size[MAX_N];
map<int,int> rev;
int tot, n, q;
 
int dfs(int u) {
    pos[u] = tot;
    list[tot] = sorted[tot] = arr[u];
    tot++;
    int ret = 1;
    for (int i = 0; i < adj[u].size(); i++) {
        ret += dfs(adj[u][i]);
    }
    return size[pos[u]] = ret;
}
 
int work(int l,int r,int val) {
    if (sorted[r].ability <= val) return -1;
    if (sorted[l].ability > val) return maxl[l];
    while (l + 1 < r) {
        int mid = (l + r) >> 1;
        if (sorted[mid].ability > val) r = mid; else l = mid;
    }
    return maxl[r];
}
 
int main() {
    int T;
    scanf("%d",&T);
    while (T--) {
        scanf("%d%d",&n, &q);
        for (int i = 0; i < n; i++) {
            adj[i].clear();
            arr[i].loyalty = arr[i].ability = -1;
            sorted[i] = list[i] = arr[i];
        }
        memset(size, 0, sizeof size);
        memset(maxl, 0, sizeof maxl);
        memset(pos, 0, sizeof pos);
        rev.clear();
        rev[-1] = -1;
        for (int i = 1; i < n; i++) {
            int fa,l,a;
            scanf("%d%d%d",&fa,&l,&a);
            adj[fa].push_back(i);
            rev[arr[i].loyalty = l] = i;
            arr[i].ability = a;
        }
        tot = 0;
        dfs(0); 
        for (int i = 0; i < n; i += MAGIC) {
            int j = i + MAGIC;
            if (j > n) break;
            sort(sorted + i, sorted + j);
            maxl[j - 1] = sorted[j - 1].loyalty;
            for (int k = j - 2; k >= i; k--) 
                maxl[k] = max(maxl[k + 1], sorted[k].loyalty);
        }
        while (q--) {
            int st; scanf("%d",&st);
            int val = arr[st].ability;
            st = pos[st];
            int ed = st + size[st] - 1;
            int ans = -1;
            for (int i = st; i <= ed;) {
                if (i % MAGIC == 0 && i + MAGIC - 1 <= ed) {
                    int tmp = work(i, i + MAGIC - 1, val);
                    if (tmp > ans) ans = tmp;
                    i += MAGIC;
                } else {
                    if (list[i].ability > val && list[i].loyalty > ans) ans = list[i].loyalty;
                    i++;
                }
            }
            printf("%d\n",rev[ans]);
        }
    }
    return 0;
}
View Code

 

posted @ 2015-08-17 10:37  mithrilhan  阅读(153)  评论(0编辑  收藏  举报