BZOJ-2588-Count on a tree(树上主席树+LCA模板)

题目
Reaper
在这里插入图片描述
题解: 每个点的前向是它的父亲,建立n(n个节点)的前缀树。
ac=lca(x,y),acfa=fa[ac][0];
left=sum[t[x].l]+sum[t[y].l]-sum[t[ac].l]-sum[t[acfa].l];
也就是 x+y-ac-acfa=x-ac+y-ac+(ac-acfa);

Sample Input
8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2

Sample Output
2
8
9
105
7

HINT:
N,M<=100000

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define m(a,b) memset(a,b,sizeof a)
#define en '\n'
using namespace std;
typedef long long ll;
const int N=1e5+5,K=17,M=N;
int a[N],refl[N],cnt;
int root[N],sum[N*50],sz;
struct tree{int l,r;}t[N*50];
int fa[N][K+5],dep[N];
int head[N],tot;
struct Edge{int to,nex;}edge[M<<1];
void add(int from,int to)
{
    edge[++tot]=(Edge){to,head[from]};head[from]=tot;
    edge[++tot]=(Edge){from,head[to]};head[to]=tot;
}
void build(int wh,int &x,int y,int l,int r)
{
    x=++sz,t[x]=t[y],sum[x]=sum[y]+1;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    if(wh<=mid)
        build(wh,t[x].l,t[y].l,l,mid);
    else
        build(wh,t[x].r,t[y].r,mid+1,r);
}
void dfs(int x)
{
    for(int i=1;(1<<i)<=dep[x];i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=head[x];i;i=edge[i].nex)
    {
        int y=edge[i].to;
        if(y==fa[x][0])
            continue;
        dep[y]=dep[x]+1;
        fa[y][0]=x;
        int dex=lower_bound(refl+1,refl+cnt+1,a[y])-refl;//T_T 当然是先建主席树啊啊!!!
        build(dex,root[y],root[x],1,cnt);
        dfs(y);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y])
        swap(x,y);
    for(int j=K;j>=0;j--)
        if(dep[x]-(1<<j)>=dep[y])
            x=fa[x][j];
    if(x==y)
        return x;
    for(int j=K;j>=0;j--)
        if(fa[x][j]!=fa[y][j])
            x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
int query(int a,int b,int c,int d,int l,int r,int k)
{
    if(l==r)
        return l;
    int mid=(l+r)>>1;
    int left=sum[t[a].l]+sum[t[b].l]-sum[t[c].l]-sum[t[d].l];
    if(left>=k)
        return query(t[a].l,t[b].l,t[c].l,t[d].l,l,mid,k);
    else
        return query(t[a].r,t[b].r,t[c].r,t[d].r,mid+1,r,k-left);
}
int main()
{
    m(head,0),tot=0;
    m(fa,-1),dep[0]=0;//这里设置了一个超级入点0,所以可以初始化为-1
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),refl[i]=a[i];
    sort(refl+1,refl+n+1);
    cnt=unique(refl+1,refl+n+1)-(refl+1);
    add(0,1);
    for(int i=1;i<=n-1;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
    }
    dfs(0);
    int lastans=0;
    while(m--)
    {
        int a,b,k;scanf("%d%d%d",&a,&b,&k);
        a^=lastans;
        int ac=lca(a,b),acfa=fa[ac][0];
        lastans=refl[query(root[a],root[b],root[ac],root[acfa],1,cnt,k)];
        printf("%d\n",lastans);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42576687/article/details/90113742
今日推荐