「SPOJ1487」Query on a tree III

「SPOJ1487」Query on a tree III

传送门
把树的 \(\text{dfs}\) 序抠出来,子树的节点的编号位于一段连续区间,然后直接上建主席树区间第 \(k\) 大即可。
参考代码:

#include <algorithm>
#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}

const int _ = 1e5 + 5;

int tot, head[_], nxt[_ << 1], ver[_ << 1];
inline void Add_edge(int u, int v)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v; }

int n, q, a[_], X[_], dfn[_], rev[_], siz[_], pos[_];
int tt, rt[_], lc[_ << 5], rc[_ << 5], cnt[_ << 5];

inline void build(int& p, int l = 1, int r = n) {
    p = ++tt;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    build(lc[p], l, mid), build(rc[p], mid + 1, r);
}

inline void update(int& p, int q, int v, int l = 1, int r = n) {
    p = ++tt, lc[p] = lc[q], rc[p] = rc[q], cnt[p] = cnt[q] + 1;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    if (v <= mid) update(lc[p], lc[q], v, l, mid);
    else update(rc[p], rc[q], v, mid + 1, r);
}

inline int query(int p, int q, int k, int l = 1, int r = n) {
    if (l == r) return l;
    int mid = (l + r) >> 1, num = cnt[lc[p]] - cnt[lc[q]];
    if (num >= k) return query(lc[p], lc[q], k, l, mid);
    else return query(rc[p], rc[q], k - num, mid + 1, r);
}

inline void dfs(int u, int f) {
    rev[dfn[u] = ++dfn[0]] = u, siz[u] = 1;
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i]; if (v == f) continue ;
        dfs(v, u), siz[u] += siz[v];
    }
}

int main() {
    read(n);
    for (rg int i = 1; i <= n; ++i) read(a[i]), X[i] = a[i];
    sort(X + 1, X + n + 1);
    for (rg int i = 1; i <= n; ++i)
        a[i] = lower_bound(X + 1, X + n + 1, a[i]) - X, pos[a[i]] = i;
    for (rg int u, v, i = 1; i < n; ++i)
        read(u), read(v), Add_edge(u, v), Add_edge(v, u);
    dfs(1, 0), build(rt[0]);
    for (rg int i = 1; i <= n; ++i) update(rt[i], rt[i - 1], a[rev[i]]);
    read(q);
    for (rg int l, r, x, k; q--; ) {
        read(x), read(k), l = dfn[x], r = dfn[x] + siz[x] - 1;
        printf("%d\n", pos[query(rt[r], rt[l - 1], k)]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zsbzsb/p/12231682.html

时间: 2024-11-07 18:08:43

「SPOJ1487」Query on a tree III的相关文章

BZOJ1803: Spoj1487 Query on a tree III

1803: Spoj1487 Query on a tree III Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 286  Solved: 125[Submit][Status] Description You are given a node-labeled rooted tree with n nodes. Define the query (x, k): Find the node whose label is k-th largest in

【BZOJ1803】Spoj1487 Query on a tree III 主席树+DFS序

[BZOJ1803]Spoj1487 Query on a tree III Description You are given a node-labeled rooted tree with n nodes. Define the query (x, k): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels. Input

「luogu2633」Count on a tree

「luogu2633」Count on a tree 传送门 树上主席树板子. 每个节点的根从其父节点更新得到,查询的时候差分一下就好了. 参考代码: #include <algorithm> #include <cstdio> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", s

「SPOJ10707」Count on a tree II

「SPOJ10707」Count on a tree II 传送门 树上莫队板子题. 锻炼基础,没什么好说的. 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w

【bzoj1803】Spoj1487 Query on a tree III DFS序+主席树

题目描述 You are given a node-labeled rooted tree with n nodes. Define the query (x, k): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels. 输入 The first line contains one integer n (1 <= n <

bzoj 1803: Spoj1487 Query on a tree III(主席树)

题意 你被给定一棵带点权的n个点的有根数,点从1到n编号. 定义查询 query(x,k): 寻找以x为根的k大点的编号(从小到大排序第k个点) 假设没有两个相同的点权. 输入格式: 第一行为整数n,第二行为点权,接下来n-1行为树边,接下来一行为整数m,下面m行为两个整数x,k,代表query(x,k) 输出格式: m行,输出每次查询的结果. 题解 先一遍dfs,然后建个主席树,带上去直接跑一跑就好了 我忘了注意dfs序的位置和原来的编号……结果调了半天啥都调不出来…… 1 //minamot

【DFS序】【莫队算法】【权值分块】bzoj1803 Spoj1487 Query on a tree III

基本等同这个,只是询问的东西不大一样而已. http://www.cnblogs.com/autsky-jadek/p/4159897.html #include<cstdio> #include<algorithm> #include<cmath> using namespace std; int Num,CH[12],f,c; inline void R(int &x){ c=0;f=1; for(;c<'0'||c>'9';c=getchar(

「CF741D」Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

传送门 Luogu 解题思路 考虑把22个字符状压下来,易知合法情况就是状态中之多有一个1,这个可以暴力一点判断23次. 然后后就是 dsu on the tree 了. 细节注意事项 咕咕咕 参考代码 #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cctype> #i

PT07J - Query on a tree III DFS序 + 主席树

dfs序编号后跑权值主席树 但写起来是真的麻烦,总是wa,只能拿出模板过了 #include<bits/stdc++.h> const int N = 100001; using namespace std; struct node { int to, ne; } e[N<<1]; int n, m, len, l1, l2; int id[N], rk[N], eid[N], re[N]; int he[N], a[N], b[N]; int val[N << 5],