【Bzoj2588】Count on a tree

本文介绍了一种在树形结构中使用主席树解决第k小权值查询的问题。通过将每个节点与其父节点关联,利用主席树进行路径查询,实现了高效的求解。文章提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

伟大的树上权值第k小。


解析

在树上建立主席树,每个点的前驱不再是它的前一个点,而是它的父亲结点。我们可以这样来想,序列上的主席树类似于前缀和,用的时候直接序列上差分。而树上也就可以把每个点保存为到根的主席树,查询的时候也类比树上的差分就可以了。


记得是Query(rt[x],rt[y]….)。

#include <cstdio>
#include <algorithm>

#define Rep( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i<=(i##_END);i++)
#define For( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i++)
#define Lop( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i>=(i##_END);i--)
#define Dnt( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i--)

using std :: max;
using std :: min;

const int maxx = 100000 + 25;

typedef int Array[maxx];

int n,m,x,y,z,tot,cnt,num,lastans,Totnum;
int head[maxx],to[maxx<<1],nxt[maxx<<1];
int rt[maxx],lc[maxx*20],rc[maxx*20],T[maxx*20];

Array a,b,v,top,dpt,son,ftr,rnk,size;

namespace Pre_Tree{

    void insert(int &i,int pre,int l,int r,int pos){
        T[i=++cnt] = T[pre] + 1;
        if(l == r) return;
        lc[i] = lc[pre];rc[i] = rc[pre];
        int mid = (l+r) >> 1;
        if(pos <= mid) insert(lc[i],lc[pre],l,mid,pos);
        if(pos >  mid) insert(rc[i],rc[pre],mid+1,r,pos);
    }

    int Query(int x,int y,int L,int Fl,int l,int r,int k){
        if(l == r) return l;
        int mid = (l+r) >> 1;
        int tmp = T[lc[x]] + T[lc[y]] - T[lc[L]] - T[lc[Fl]];
        if(tmp <  k) return Query(rc[x],rc[y],rc[L],rc[Fl],mid+1,r,k - tmp);
        if(tmp >= k) return Query(lc[x],lc[y],lc[L],lc[Fl],l,mid,k) ;
    }

}

using namespace Pre_Tree;

namespace Cute{

    void Ins(int x,int y){
        to[++num] = y;nxt[num] = head[x];head[x] = num;
    }

    void Dfs(int x){
        size[x] = 1;
        insert(rt[x],rt[ftr[x]],1,Totnum,v[x]);
        for(int i=head[x];i;i=nxt[i]){
            if(to[i] == ftr[x]) continue;
            dpt[to[i]] = dpt[x] + 1;
            ftr[to[i]] = x;
            Dfs(to[i]);size[x] += size[to[i]];
            if(size[to[i]] > size[son[x]]) son[x] = to[i];
        }
    }

    void __Dfs(int x,int brn){
        rnk[x] = ++tot;top[x] = brn;
        if(son[x]) __Dfs(son[x],brn);
        for(int i=head[x];i;i=nxt[i])
            if(to[i] != son[x] && to[i] != ftr[x])
                __Dfs(to[i],to[i]);
    }

    int Lca(int x,int y){
        while(top[x] != top[y]){
            if(dpt[top[x]] > dpt[top[y]]) std :: swap(x,y);
            y = ftr[top[y]];
        }
        return dpt[x] < dpt[y]? x : y;
    }

}

using namespace Cute;

int main(){
    scanf("%d%d",&n,&m);
    Rep( i , 1 , n ) scanf("%d",&a[i]),b[i] = a[i];
    std :: sort(b+1,b+n+1);
    Totnum = std :: unique(b+1,b+n+1) - b - 1;
    Rep( i , 1 , n ) v[i] = std :: lower_bound(b+1,b+Totnum+1,a[i]) - b;
    For( i , 1 , n ) scanf("%d%d",&x,&y),Ins(x,y),Ins(y,x);
    Dfs(1);__Dfs(1,1);
    while( m-- ){
        scanf("%d%d%d",&x,&y,&z);
        x ^= lastans;
        lastans = b[Query(rt[x],rt[y],rt[Lca(x,y)],rt[ftr[Lca(x,y)]],1,Totnum,z)];
        printf("%d",lastans);
        if(m != 0) putchar(10);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值