BZOJ 2588: Spoj 10628. Count on a tree | 树上主席树

题目:

求树上两点之间第k小点权


题解:

对每个节点到根节点的路径建一棵线段树,这样每个点的线段树都从他父亲得到

对于询问(u,v),sum[u]+sum[v]-sum[lca]-sum[fa[lca]]可以表示u到v的路径

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 200010
using namespace std;
int root[N],fa[N],n,m,lastans,w[N],head[N],b[N],lim,pcnt,anc[N][25],ecnt,deep[N];
struct node {int lc,rc,sum;}t[N*20];
struct edge {int nxt,v;}e[2*N];
void add(int u,int v)
{
    e[++ecnt].v=v;e[ecnt].nxt=head[u];head[u]=ecnt;
    e[++ecnt].v=u;e[ecnt].nxt=head[v];head[v]=ecnt;
}
void Insert(int x,int &y,int l,int r,int k)
{
    t[y=++pcnt]=t[x];t[y].sum++;
    if (l==r) return ;
    int mid=l+r>>1;
    if (k<=mid) Insert(t[x].lc,t[y].lc,l,mid,k);
    else Insert(t[x].rc,t[y].rc,mid+1,r,k);
}
void dfs(int u)
{
    deep[u]=deep[anc[u][0]]+1;
    Insert(root[anc[u][0]],root[u],1,lim,w[u]);
    for (int i=head[u],v;i;i=e[i].nxt)
    if (e[i].v!=anc[u][0])
        anc[v=e[i].v][0]=u,dfs(v);
}
int lca(int x,int y)
{
    if (deep[x]<deep[y]) swap(x,y);
    for (int i=20;i>=0;i--)
        if (deep[anc[x][i]]>=deep[y]) 
            x=anc[x][i];
    if (x==y) return x;
    for (int i=20;i>=0;i--)
        if (anc[x][i]!=anc[y][i])
            x=anc[x][i],y=anc[y][i];
    return anc[x][0];
}
int query(int u,int v,int k)
{
    int GGfa=lca(u,v),tmp[4]={root[u],root[v],root[GGfa],root[anc[GGfa][0]]},val,l=1,r=lim,mid;
    while (l<r)
    {
          mid=l+r>>1;
           val=t[t[tmp[0]].lc].sum+t[t[tmp[1]].lc].sum-t[t[tmp[2]].lc].sum-t[t[tmp[3]].lc].sum;
           if (k<=val)
        {
            r=mid;
                for (int i=0;i<4;i++)
                tmp[i]=t[tmp[i]].lc;
           }    
           else
            {
               l=mid+1;k-=val;
               for (int i=0;i<4;i++)
                   tmp[i]=t[tmp[i]].rc;
            }
    }
    return b[l];
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) 
        scanf("%d",w+i),b[i]=w[i];
    sort(b+1,b+n+1);
    lim=unique(b+1,b+1+n)-b-1;
    for (int i=1;i<=n;i++)
        w[i]=lower_bound(b+1,b+1+lim,w[i])-b;
    for (int i=1,u,v;i<n;i++)
           scanf("%d%d",&u,&v),add(u,v);
    dfs(1);
    for (int j=1;j<=20;j++)
        for (int i=1;i<=n;i++)
               anc[i][j]=anc[anc[i][j-1]][j-1];
    for (int i=1,u,v,k;i<=m;i++)
    {
          scanf("%d%d%d",&u,&v,&k);
          printf("%d",lastans=query(u^lastans,v,k));
           if (i<m) printf("\n");
    }
    return 0;
}

 

posted @ 2017-12-31 19:28  MSPqwq  阅读(122)  评论(0编辑  收藏  举报