BZOJ2588: Count on a tree 树上主席树

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u和v这两个节点间第K小的点权,强制在线。N,M<=100000
边DFS边建出主席树,这样每次建出的树存储的都是该节点到根的 size 前缀和
这样每次在 rt[u]+rt[v]rt[lca]rt[fa[lca]] 四棵树上查询即可

/**************************************************************
    Problem: 2588
    User: bdzxt
    Language: C++
    Result: Accepted
    Time:4844 ms
    Memory:47508 kb
****************************************************************/

#include
#define LL long long 
#define clr(x,i) memset(x,i,sizeof(x))
using namespace std;
const int N=100005;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct Edge{
    int to,nex;
}e[N*2];
struct Node{
    int l,r,sz;
}t[N*25];
int n,m,A[N],rk[N],sz,head[N],pa[N],fa[N][19],dep[N],dfn,ecnt;
int rt[N],tot;
inline void addedge(int u,int v)
{
    e[++ecnt]=(Edge){v,head[u]};head[u]=ecnt;
    e[++ecnt]=(Edge){u,head[v]};head[v]=ecnt;
}
void upd(int l,int r,int &x,int y,int p)
{
    x=++tot;t[x]=t[y];t[x].sz++;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(p<=mid)
      upd(l,mid,t[x].l,t[y].l,p);
    else
      upd(mid+1,r,t[x].r,t[y].r,p);
}
int query(int l,int r,int a,int b,int c,int d,int k)
{
    if(l==r) return l;
    int sum=t[t[a].l].sz+t[t[b].l].sz-t[t[c].l].sz-t[t[d].l].sz,mid=(l+r)>>1;
    if(k<=sum)
      return query(l,mid,t[a].l,t[b].l,t[c].l,t[d].l,k);
    else
      return query(mid+1,r,t[a].r,t[b].r,t[c].r,t[d].r,k-sum);
}
void dfs(int u)
{
    //tid[u]=++dfn;pos[dfn]=u;
    int val=lower_bound(rk+1,rk+sz+1,A[u])-rk;
    upd(1,sz,rt[u],rt[pa[u]],val);
    for(int i=head[u];i;i=e[i].nex){
        int v=e[i].to;if(v==pa[u])continue;
        pa[v]=u;dep[v]=dep[u]+1;
        dfs(v);
    }
}
int LCA(int x,int y)
{
    if(dep[x]for(int i=18;i>=0;i--)
      if(dep[fa[x][i]]>=dep[y])
        x=fa[x][i];
    if(x==y)return x;
    for(int i=18;i>=0;i--)
      if(fa[x][i]!=fa[y][i])
        x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++) A[i]=rk[i]=read();
    sort(rk+1,rk+n+1);
    sz=unique(rk+1,rk+n+1)-rk-1;
    for(int i=1;iint u=read(),v=read();addedge(u,v);
    }
    dep[1]=1;dfs(1);
    for(int i=1;i<=n;i++)fa[i][0]=pa[i];
    for(int j=1;j<=18;j++)
      for(int i=1;i<=n;i++)
        fa[i][j]=fa[fa[i][j-1]][j-1];
    int lastans=0;
    for(int i=1;i<=m;i++)
    {
        int u=read()^lastans,v=read(),k=read(),lca=LCA(u,v);
        lastans=rk[query(1,sz,rt[u],rt[v],rt[lca],rt[pa[lca]],k)];//记得加rt 
        printf("%d",lastans);
        if(i!=m)putchar('\n');
    }
    return 0;
}

你可能感兴趣的:(BZOJ,主席树,dfs)