zoukankan      html  css  js  c++  java
  • 【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
    " , r[query(y , 1 , n , root[pos[x] - 1] , root[last[x]])]); 
        return 0; 
    }
    
  • 相关阅读:
    Attach Files to Objects 将文件附加到对象
    Provide Several View Variants for End-Users 为最终用户提供多个视图变体
    Audit Object Changes 审核对象更改
    Toggle the WinForms Ribbon Interface 切换 WinForms 功能区界面
    Change Style of Navigation Items 更改导航项的样式
    Apply Grouping to List View Data 将分组应用于列表视图数据
    Choose the WinForms UI Type 选择 WinForms UI 类型
    Filter List Views 筛选器列表视图
    Make a List View Editable 使列表视图可编辑
    Add a Preview to a List View将预览添加到列表视图
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6938468.html
Copyright © 2011-2022 走看看