【Luogu P2633 】Count on a tree

题目链接

题目描述

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

题解

主席树静态区间第K小的树上情况。
只要把序列上的变成按父子关系来就行,用DFS序。

求的时候因为是点权,记录每一个点到根的信息后,用两端的减去lca的和lca的父亲的即可。

代码如下:

//树上的前缀
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();int t=1;
    for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-48;
    return x*t;
}
const int N=1e5+100;
struct node{int ls;int rs;int sum;inline void clear(){ls=rs=sum=0;}};
struct edge{int to,next;}a[N<<1];
int head[N];int cnt=0,m;
node tr[N<<5];int cn=0;int rt[N];
int n;int w[N];int ID[N];int num;
inline void add(int x,int y){a[++cnt]=(edge){y,head[x]};head[x]=cnt;}
int deep[N],top[N],son[N];int fa[N];
inline int Get(int u){return (lower_bound(ID+1,ID+1+num,w[u])-ID);}
inline void update(int &u,int l,int r,int p)
{
    tr[++cn]=tr[u];u=cn;
    ++tr[u].sum;
    if(l==r) return;
    register int mid=l+r>>1;
    if(mid>=p) update(tr[u].ls,l,mid,p);
    else update(tr[u].rs,mid+1,r,p);
}
inline int dfs1(int u,int ff){
    deep[u]=deep[ff]+1;fa[u]=ff;register int si=1;register int maxn_si=-1;
    rt[u]=rt[ff];update(rt[u],1,num,Get(u));
    for(register int v,i=head[u];i;i=a[i].next){
        v=a[i].to;if(v==ff) continue;
        register int ss=dfs1(v,u);if(ss>maxn_si) son[u]=v,maxn_si=ss;si+=ss;
    }
    return si;
}
inline void dfs2(int u,int ff)
{
    top[u]=ff;if(!son[u]) return;dfs2(son[u],ff);
    for(register int v,i=head[u];i;i=a[i].next){v=a[i].to;if(v==son[u]||v==fa[u]) continue;dfs2(v,v);}
}
inline int LCA(int x,int y)
{
    while(top[x]!=top[y]){if(deep[top[x]]return deep[x]>deep[y]? y:x;
}
inline void build(int &u,int l,int r)
{
    if(!u) u=++cn;if(l==r) return;
    register int mid=l+r>>1;
    build(tr[u].ls,l,mid);build(tr[u].rs,mid+1,r);
}
inline int Query(int u1,int u2,int u3,int u4,int l,int r,int k)
{
    if(l==r) return l;
    register int sum=tr[tr[u1].ls].sum+tr[tr[u2].ls].sum-tr[tr[u3].ls].sum-tr[tr[u4].ls].sum;
    register int mid=l+r>>1;
    if(sum>=k) return Query(tr[u1].ls,tr[u2].ls,tr[u3].ls,tr[u4].ls,l,mid,k);
    else return Query(tr[u1].rs,tr[u2].rs,tr[u3].rs,tr[u4].rs,mid+1,r,k-sum);
}
int main()
{
    n=read();m=read();
    for(register int i=1;i<=n;++i) w[i]=ID[i]=read();
    sort(ID+1,ID+1+n);num=unique(ID+1,ID+1+n)-ID-1;
    build(rt[0],1,num);//建空树就可以直接不用管有的儿子不存在的情况了
    register int x,y,k;
    for(register int i=1;i1,0);
    dfs2(1,1);
    int lst=0;
    for(register int i=1;i<=m;++i){
        x=read();y=read();k=read();
        x^=lst;int lca=LCA(x,y);
        lst=ID[Query(rt[x],rt[y],rt[lca],rt[fa[lca]],1,num,k)];
        printf("%d\n",lst);

    }
}

你可能感兴趣的:(======题解======,主席树)