[BZOJ2588]Spoj 10628. Count on a tree

题意

给定一个有n个结点的树,在线询问两个点之间路径上第k大的点的点权是多少。

分析

其实刚开始看到这道题的想法是树链剖分出log条链在同时在可持久化线段树上查询第k大。但是这样写起来并不优雅而且很难写。
然后考虑每次其实相当于取出两条点到某个祖先的链找第k大,所以这里的可持久化线段树可以不基于dfs序,而是直接用父亲结点的线段树。
然后这样就只需要求一个lca,然后开始的时候建一棵可持久化线段树即可。

code

//201806月09日 星期六 101617#include<bits/stdc++.h>
#define M 100005
using namespace std;
void read(int &x){
    x=0; char c=getchar();
    for (;c<48;c=getchar());
    for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
}

struct ed{
    int x,nx;
}e[M<<1];
int a[M],b[M],rt[M],fa[M],top[M],son[M],de[M],nx[M],ecnt=1,cnt[M];

void add(int x,int y){
    e[ecnt]=(ed){y,nx[x]};
    nx[x]=ecnt++;
}
int ch(int l,int r,int x){
    int mid;
    for (;l<=r;){
        mid=(l+r)>>1;
        if (b[mid]==x)return mid;
        if (b[mid]<x)l=mid+1;
        else r=mid-1;
    }
}

struct Tree{
    int tot,f[M*30],rs[M*30],ls[M*30];
    void build(int l,int r,int &p){
        p=++tot;
        if (l==r)return;
        int mid=(l+r)>>1;
        build(l,mid,ls[p]);
        build(mid+1,r,rs[p]);
    }
    void build(int l,int r,int x,int lp,int &p){
        p=++tot;
        ls[p]=ls[lp];
        rs[p]=rs[lp];
        f[p]=f[lp]+1;
        if (l==r){
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid)build(l,mid,x,ls[lp],ls[p]);
        else build(mid+1,r,x,rs[lp],rs[p]);
    }
    int qu(int l,int r,int k,int p1,int p2,int p3,int p4){
        if (l==r)return l;
        int sum=(f[ls[p1]]+f[ls[p2]]-f[ls[p3]]-f[ls[p4]]),mid=(l+r)>>1;
        if (sum>=k)return qu(l,mid,k,ls[p1],ls[p2],ls[p3],ls[p4]);
        else return qu(mid+1,r,k-sum,rs[p1],rs[p2],rs[p3],rs[p4]);
    }
    void pt(int l,int r,int p){
        if (l==r){
            printf("%d ",f[p]);
            return ;
        }
        int mid=(l+r)>>1;
        pt(l,mid,ls[p]);
        pt(mid+1,r,rs[p]);
    }
}T;
int tot;
void dfs1(int f,int x){
    fa[x]=f; cnt[x]=1; de[x]=de[f]+1; son[x]=0;
    for (int i=nx[x];i;i=e[i].nx)if (e[i].x!=f){
        dfs1(x,e[i].x);
        cnt[x]+=cnt[e[i].x];
        if (cnt[e[i].x]>cnt[son[x]])son[x]=e[i].x;
    }
}
void dfs2(int f,int x){
    top[x]=f;
    T.build(1,tot,a[x],rt[fa[x]],rt[x]);
    if (son[x])dfs2(f,son[x]);
    for (int i=nx[x];i;i=e[i].nx)if(e[i].x!=fa[x]&&e[i].x!=son[x]){
        dfs2(e[i].x,e[i].x);
    }
}
int lca(int x,int y){
    for (;top[x]!=top[y];){
        if (de[top[x]]>de[top[y]])x=fa[top[x]];
        else y=fa[top[y]];
    }
    if (de[x]<de[y])return x;
    return y;
}
int qu(int x,int y,int k){
    int Lca=lca(x,y);
    return T.qu(1,tot,k,rt[x],rt[y],rt[Lca],rt[fa[Lca]]);
}
int main(){
//  freopen("1.in","r",stdin);
    int n,m,i,x,y,res=0,k;
    read(n); read(m);
    for (i=1;i<=n;i++)read(a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    tot=unique(b+1,b+n+1)-b-1;
    for (i=1;i<=n;i++)a[i]=ch(1,tot,a[i]);
    for (i=1;i<n;i++){
        read(x); read(y);
        add(x,y); add(y,x);
    }
    T.build(1,tot,rt[0]);
    dfs1(0,1);
    dfs2(1,1);
//  for (i=1;i<=n;i++)printf("------%d-------\n",i),T.pt(1,tot,rt[i]),printf("\n");
    for (;m--;){
        read(x); read(y); read(k);
        x^=res;
        res=b[qu(x,y,k)];
        printf("%d",res);
        if (m)puts("");
    }
    return 0;
}

其实是很裸的题?qwq我太弱了

猜你喜欢

转载自blog.csdn.net/Umbrella__/article/details/80671152