洛谷 2633 Count on a tree

题目是一个n个点的数,q次询问,每次询问回答一条路径上第k小数。

在树上建主席树,每个点的状态可以从父亲节点得到。

求答案时答案由路径两个端点的权值线段树之和减去lca和lca父亲节点的权值线段树之和。

因为两个端点的权值线段树之和会多算一次跟节点到lca路径上出现的权值以及根节点到lca父亲节点路径上出现的权值。

 

 

#include <bits/stdc++.h>
using namespace std;
const int M = 1e5+7;
int n,q,tot,pos;
int a[M],ls[M],sz;
/************lca***************/
int cnt,head[M];
struct edge
{
    int v,next;
}e[M<<1];
void init(){
    tot=cnt=0;memset(head,-1,sizeof(head));
}
void add(int u,int v){
    e[++cnt].v=v;e[cnt].next=head[u];
    head[u]=cnt;
}
int f[M][22],fat[M],deep[M];
void dfs(int u,int fa,int d){
    deep[u]=d;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa) continue;
        dfs(v,u,d+1);
        f[v][0]=u;
        fat[v]=u;
    }
    return ;
}
void work(){//RMQ
    for(int i=1;i<20;i++)
        for(int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1];
}
int lca(int x,int y){//lca
    if(deep[x]<deep[y]) swap(x,y);
    int dt=deep[x]-deep[y];
    for(int i=0;i<20;i++) if(dt&(1<<i)) x=f[x][i];
    if(x==y) return x;
    for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
/***********************zhuxishu*******************/
int L[20*M],R[20*M],num[20*M],T[M];
void build(int l,int r,int rt){
    rt=++tot;
    num[rt]=0;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(l,mid,L[rt]);
    build(mid+1,r,R[rt]);
}
void update(int l,int r,int &rt,int pre){
    rt=++tot;
    num[rt]=num[pre]+1;
    if(l==r) return ;
    L[rt]=L[pre];R[rt]=R[pre];
    int mid=(l+r)>>1;
    if(pos<=mid) update(l,mid,L[rt],L[pre]);
    else update(mid+1,r,R[rt],R[pre]);
}
int query(int l,int r,int xrt,int yrt,int lcart,int lcafa,int k){
    if(l==r) return l;
    int mid=(l+r)>>1,sum=num[L[xrt]]+num[L[yrt]]-num[L[lcart]]-num[L[lcafa]];
    if(sum>=k) return query(l,mid,L[xrt],L[yrt],L[lcart],L[lcafa],k);
    else return query(mid+1,r,R[xrt],R[yrt],R[lcart],R[lcafa],k-sum);
}
/****************************solve**********************************/
void dfs_build(int u,int fa){
    pos=lower_bound(ls+1,ls+sz+1,a[u])-ls;
    update(1,sz,T[u],T[fa]);
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa) continue;
        dfs_build(v,u);
    }
}
void solve(){
    int preans=0;
    dfs(1,-1,0);
    work();
    build(1,sz,T[0]);
    dfs_build(1,0);
    while(q--){
        int u,v,k;
        scanf("%d%d%d",&u,&v,&k);
        u=u^preans;
        preans=ls[query(1,sz,T[u],T[v],T[lca(u,v)],T[fat[lca(u,v)]],k)];
        printf("%d\n", preans);
    }
}
/**************************main*************************/
int main(){
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    init();
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),ls[i]=a[i];
    sort(ls+1,ls+n+1);
    sz=unique(ls+1,ls+n+1)-ls-1;
    for(int i=1;i<n;i++){
        int from,to;
        scanf("%d%d",&from,&to);
        add(from,to);add(to,from);
    }
    solve();
    return 0;
}
View Code

 

posted @ 2018-08-31 14:46  LMissher  阅读(169)  评论(0)    收藏  举报