【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 <= 10^5). The next line contains n integers li (0 <= li <= 109) which denotes the label of the i-th node. Each line of the following n - 1 lines contains two integers u, v. They denote there is an edge between node u and node v. Node 1 is the root of the tree. The next line contains one integer m (1 <= m <= 10^4) which denotes the number of the queries. Each line of the next m contains two integers x, k. (k <= the total node number in the subtree of x)

输出

For each query (x, k), output the index of the node whose label is the k-th largest in the subtree of the node x.

样例输入

5 1 3 5 2 7 1 2 2 3 1 4 3 5 4 2 3 4 1 3 2 3 2

样例输出

5 4 5 5



题目大意

给出一棵以1为根的树,每个点有一个点权。多次询问每个点为根的子树中权值第k小的点是哪个

题解

DFS序+主席树

我也不知道为什么k-th largest number是第k小的意思。反正第k小既能解释样例又能A题。

维护一个DFS序,然后子树就转化为一段连续的区间,我们要求区间第k小。

直接裸上主席树即可。

#include <cstdio>
#include <algorithm>
#define N 100010
using namespace std;
int w[N] , s[N] , r[N] , head[N] , to[N << 1] , nxt[N << 1] , cnt , pos[N] , v[N] , last[N] , tot , root[N] , ls[N * 18] , rs[N * 18] , si[N * 18] , num;
void add(int x , int y)
{
    to[++cnt] = y , nxt[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x , int fa)
{
    int i;
    pos[x] = ++tot , v[tot] = w[x];
    for(i = head[x] ; i ; i = nxt[i]) if(to[i] != fa) dfs(to[i] , x);
    last[x] = tot;
}
void ins(int p , int l , int r , int x , int &y)
{
    y = ++num , si[y] = si[x] + 1;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(p <= mid) rs[y] = rs[x] , ins(p , l , mid , ls[x] , ls[y]);
    else ls[y] = ls[x] , ins(p , mid + 1 , r , rs[x] , rs[y]);
}
int query(int k , int l , int r , int x , int y)
{
    if(l == r) return l;
    int mid = (l + r) >> 1;
    if(k <= si[ls[y]] - si[ls[x]]) return query(k , l , mid , ls[x] , ls[y]);
    else return query(k - si[ls[y]] + si[ls[x]] , mid + 1 , r , rs[x] , rs[y]);
}
int main()
{
    int n , m , i , x , y;
    scanf("%d" , &n);
    for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &w[i]) , s[i] = w[i];
    sort(s + 1 , s + n + 1);
    for(i = 1 ; i <= n ; i ++ ) w[i] = lower_bound(s + 1 , s + n + 1 , w[i]) - s , r[w[i]] = i;
    for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
    dfs(1 , 0);
    for(i = 1 ; i <= n ; i ++ ) ins(v[i] , 1 , n , root[i - 1] , root[i]);
    scanf("%d" , &m);
    while(m -- ) scanf("%d%d" , &x , &y) , printf("%d\n" , r[query(y , 1 , n , root[pos[x] - 1] , root[last[x]])]);
    return 0;
}
时间: 2024-10-25 11:32:36

【bzoj1803】Spoj1487 Query on a tree III DFS序+主席树的相关文章

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],

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

【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(

【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

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

Codeforces 620E New Year Tree(DFS序+线段树)

题目大概说给一棵树,树上结点都有颜色(1到60),进行下面两个操作:把某结点为根的子树染成某一颜色.询问某结点为根的子树有多少种颜色. 子树,显然DFS序,把子树结点映射到连续的区间.而注意到颜色60种,这样就可以用一个64位整型去表示颜色的集合,然后就是在这个连续区间中用线段树成段更新颜色集合和区间查询颜色集合了. 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 #define MAXN 500000

BZOJ 3439: Kpm的MC密码( trie + DFS序 + 主席树 )

把串倒过来插进trie上, 那么一个串的kpm串就是在以这个串最后一个为根的子树, 子树k大值的经典问题用dfs序+可持久化线段树就可以O(NlogN)解决 ------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<cctype> using namespa

BZOJ 3011: [Usaco2012 Dec]Running Away From the Barn( dfs序 + 主席树 )

子树操作, dfs序即可.然后计算<=L就直接在可持久化线段树上查询 ------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; #define M(l, r) (((l) + (r)) >> 1) const int maxn = 200009; typedef long long ll; inline ll

CodeForces 547E:Mike and Friends(AC自动机+DFS序+主席树)

What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercase English letters. What is double strange that a phone number can be associated with several bears! In that country there is a rock band called CF con