SP1487 PT07J

SP1487 PT07J - 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行,输出每次查询的结果。

Translated by @vegacx

题目描述

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}5 ). The next line contains n integers _l {i}i​ (0 <= _l {i}i​ <= 10 ^{9}9 ) 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}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.

输入输出样例

输入样例#1:

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

输出样例#1:

5
4
5
5

Solution

传送门
树上静态主席树...

显然我们要根据dfs序来建立主席树,也正因如此,所以我们在dfs的过程中要重新赋一下值,给当前dfs序为i的节点另开两个存值的数组,一个是原数组,一个离散数组,这样值才能与主席树对上号


void dfs(int u,int fa) {
    id[u]=++cnt, a[cnt]=b[cnt]=w[u], inv[cnt]=u, size[u]=1;//inv[]存的是通过dfs序找到节点
    for (int i=head[u];i;i=nex[i]) {
        if (to[i]==fa) continue;
        dfs(to[i],u); size[u]+=size[to[i]];
    }
}

在加入节点的过程中,因为题目问的是节点编号而不是值,我们还要把当前值赋为节点编号

至于查询,就是以dfs序和子树大小来查,因为是连续的...
其实如果会静态主席树,这道题稍微难一点的主要还是建树,会建树就会查询了

Code

#include<bits/stdc++.h>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define rg register
#define mid ((l+r)>>1)
#define in(i) (i=read())
using namespace std;

const int N=1e5+10;

int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();
    return ans*=f;
}

int T,n,m,tot,cur,cnt;
int w[N],a[N],b[N],id[N],inv[N],size[N],ans[N];
int to[N<<1],nex[N<<1],head[N];
int rt[N<<5],lc[N<<5],rc[N<<5],sum[N<<5];

void add(int a,int b) {
    to[++cur]=b,nex[cur]=head[a],head[a]=cur;
    to[++cur]=a,nex[cur]=head[b],head[b]=cur;
}

void build(int &u,int l,int r) {
    u=++tot,sum[u]=0;
    if (l==r) return;
    build(lc[u],l,mid);
    build(rc[u],mid+1,r);
}

void update(int &u,int l,int r,int pre,int x) {
    u=++tot;
    sum[u]=sum[pre]+1,lc[u]=lc[pre],rc[u]=rc[pre];
    if (l==r) return;
    if(x<=mid) update(lc[u],l,mid,lc[pre],x);
    else update(rc[u],mid+1,r,rc[pre],x);
}

int query(int u,int v,int l,int r,int k) {
    if(l==r) return ans[l];
    int rest=sum[lc[v]]-sum[lc[u]];
    if(k<=rest) return query(lc[u],lc[v],l,mid,k);
    else return query(rc[u],rc[v],mid+1,r,k-rest);
}

void dfs(int u,int fa) {
    id[u]=++cnt, a[cnt]=b[cnt]=w[u], inv[cnt]=u, size[u]=1;
    for (int i=head[u];i;i=nex[i]) {
        if (to[i]==fa) continue;
        dfs(to[i],u); size[u]+=size[to[i]];
    }
}

int main()
{
    in(n);
    for (int i=1;i<=n;i++) in(w[i]);
    for (int i=1,x,y;i<n;i++) in(x), in(y), add(x,y);
    dfs(1,0);
    sort(b+1,b+1+n); build(rt[0],1,n);
    for (int i=1;i<=n;i++) {
        a[i]=lower_bound(b+1,b+1+n,a[i])-b;
        ans[a[i]]=inv[i];
        update(rt[i],1,n,rt[i-1],a[i]);
    }
    in(m);
    for (int i=1,x,k;i<=m;i++) {
        in(x), in(k);
        printf("%d
",query(rt[id[x]-1],rt[id[x]+size[x]-1],1,n,k));
    }
}

原文地址:https://www.cnblogs.com/real-l/p/9873035.html