2270-The Lth Number

解法

セグメント木を永続データー構造化し,その上で二分探索する.
割と遅め.

実装(C++)

#include <vector>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
struct Persistent_Segtree{
  int n;
  struct Node{
    Node *left,*right;
    int value;
    Node(){
      left=right=0;value=0;
    }
  };
  vector<Node> roots;
  void dfs(Node *node,int left,int right){
    if(right-left==1)return;
    node->left=new Node();
    node->right=new Node();
    dfs(node->left,left,(left+right)/2);
    dfs(node->right,(left+right)/2,right);
  }
  Persistent_Segtree(int n){
    int N=1;
    while(N<=n){
      N<<=1;
    }
    this->n=N;
    Node root;
    dfs(&root,0,N);
    roots.push_back(root);
  }
  void add_term(Node *node,int l,int r,int x,int k){
    if(l<=x&&x<r){
      node->value+=k;
      if(r-l==1)return;
      if(x<(l+r)/2){
        Node tmp=*node->left;
        node->left=new Node();
        *node->left=tmp;
        add_term(node->left,l,(l+r)/2,x,k);
      }else{
        Node tmp=*node->right;
        node->right=new Node();
        *node->right=tmp;
        add_term(node->right,(l+r)/2,r,x,k);
      }
    }
  }
  int add(int x,int k,int target=-1){
    if(target==-1)target=roots.size()-1;
    Node rts;
    rts=roots[target];
    add_term(&rts,0,n,x,k);
    roots.push_back(rts);
    return roots.size()-1;
  }
  int sum(int k,int l,int r){
    return sum(&roots[k],l,r,0,n);
  }
  int sum(Node *node,int l,int r,int L,int R){
    if(l<=L&&R<=r)return node->value;
    if(r<=L||R<=l)return 0;
    return sum(node->left,l,r,L,(L+R)/2)+sum(node->right,l,r,(L+R)/2,R);
  }
};
int readint(){
  int x;
  scanf("%d",&x);
  return x;
}
int val[100000];
int v_[100000];
int N,Q;
vector<int> G[100000];
int parent[18][100000];
int depth[100000];
void dfs(int s,int b,int d=0){
  parent[0][s]=b;
  depth[s]=d;
  for(int i=0;i<(int)G[s].size();i++){
    if(G[s][i]==b)continue;
    dfs(G[s][i],s,d+1);
  }
}
 
void init(){
  for(int i=1;i<log2(N)+1;i++){
    for(int j=0;j<N;j++){
      if(parent[i-1][j]!=-1){
        parent[i][j]=parent[i-1][parent[i-1][j]];
      }
    }
  }
}
 
int getLCA(int x,int y){
  if(depth[x]<depth[y])return getLCA(y,x);
  int d=depth[x]-depth[y];
  for(int i=0;i<log2(N)+1;i++){
    if(d>>i&1)x=parent[i][x];
  }
  if(x==y)return x;
  for(int i=log2(N);i>=0;i--){
    if(parent[i][x]!=parent[i][y]){
      x=parent[i][x];
      y=parent[i][y];
    }
  }
  return parent[0][x];
}
int no[1000000];
 
void dfs_d(int n,int b,Persistent_Segtree &bit){
  no[n]=bit.add(lower_bound(v_,v_+N,val[n])-v_,1,no[b]);
  for(int i=0;i<(int)G[n].size();i++){
    if(G[n][i]==b)continue;
    dfs_d(G[n][i],n,bit);
  }
     
}
int main(){
  N=readint();
  Q=readint();
  memset(parent,-1,sizeof(parent));
  for(int i=0;i<N;i++)v_[i]=val[i]=readint();
  for(int i=0;i<N-1;i++){
    int a,b;
    a=readint()-1;
    b=readint()-1;
    G[a].push_back(b);
    G[b].push_back(a);
  }
  Persistent_Segtree bit(N);
  dfs(0,-1);
  sort(v_,v_+N);
  dfs_d(0,0,bit);
  init();
  for(int i=0;i<Q;i++){
    int l,r,k;
    scanf("%d%d%d",&l,&r,&k);
    l--;r--;
    k--;
    int tar=getLCA(l,r);
    int tar2=getLCA(l,r);
     
    tar=parent[0][tar];
    int low=-1,high=N-1;
    while(high>low+1){
      int mid=(low+high)/2;
      int tmp=bit.sum(no[r],0,mid+1)+bit.sum(no[l],0,mid+1)-bit.sum(no[tar2],0,mid+1);
      if(tar>=0){
        tmp-=bit.sum(no[tar],0,mid+1);
      }
      if(tmp>k){
        high=mid;
      }else{
        low=mid;
      }
    }
    printf("%dn",v_[high]);
  }
}