SPOJ Count on a tree 主席树+lca

传送门

题意:给你一棵树,询问u到v路径上的第k大

题解:从u到v的路径能想到,u到根+v到根-lca(u,v)到根-fa[lca(u,v)]到根剩下的就是u到v之间的路径。因此只要离散化一下,每次dfs的时候处理倍增lca和主席树更新操作就可以

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
#include <iomanip>
#include <set>
#include<ctime>
//CLOCKS_PER_SEC
#define se second
#define fi first
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Pii pair<int,int>
#define Pli pair<ll,int>
#define ull unsigned long long
#define pb push_back
#define fio ios::sync_with_stdio(false);cin.tie(0)
const double Pi=3.14159265;
const int N=1e5+10;
const ull base=163;
const int INF=0x3f3f3f3f;
using namespace std;
int n,m, root[N], a[N],cnt=0;
struct node {
    int l,r,sum;
}T[40*N];
int New[N];
int fa[N][20];
int dep[N];
vector<int>v;
int head[N],to[2*N],nx[2*N],tot=1;
void add(int u,int v){
    to[tot]=v;
    nx[tot]=head[u];
    head[u]=tot++;
}
int getid(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
void update(int l,int r,int &x,int y,int pos){
    T[++cnt]=T[y],T[cnt].sum++,x=cnt;
    if(l==r)return ;
    int m=(l+r)>>1;
    if(pos<=m)update(l,m,T[x].l,T[y].l,pos);
    else update(m+1,r,T[x].r,T[y].r,pos);
}
void dfs(int u,int  pre){
    fa[u][0]=pre;
    dep[u]=dep[pre]+1;
    update(1,n,root[u],root[pre],New[u]);
    for(int i=1;i<17;i++){
        fa[u][i]=fa[fa[u][i-1]][i-1];
    }
    for(int i=head[u];i;i=nx[i]){
        int v=to[i];
        if(pre==v)continue;
        dfs(v,u);
    }
}
int LCA(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    int d=dep[u]-dep[v];
    for(int i=0;(1<<i)<=d;i++){
        if((1<<i)&d)u=fa[u][i];
    }
    if(u==v)return u;
    for(int i=16;i>=0;i--){
        if(fa[v][i]!=fa[u][i]){
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    return fa[u][0];
}
int query(int l,int r,int k,int x,int y,int z,int w){
    if(l==r)return l;
    int m=(l+r)>>1;
    int d=T[T[x].l].sum+T[T[y].l].sum-T[T[z].l].sum-T[T[w].l].sum;
    if(d>=k)return query(l,m,k,T[x].l,T[y].l,T[z].l,T[w].l);
    else return query(m+1,r,k-d,T[x].r,T[y].r,T[z].r,T[w].r);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),v.pb(a[i]);
    sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());
    for(int i=1;i<=n;i++)New[i]=getid(a[i]);
    for(int i=1;i<=n-1;i++){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs(1,0);
    for(int i=1;i<=m;i++){
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",v[query(1,n,k,root[l],root[r],root[LCA(l,r)],root[fa[LCA(l,r)][0]])-1]);
    }
    return 0;
}

 

posted @ 2018-05-27 22:38  采蘑菇的小西佬  阅读(119)  评论(0编辑  收藏  举报