[bzoj2588][Spoj10628]Count on a tree_主席树

Count on a tree bzoj-2588 Spoj-10628

题目大意:给定一棵n个点的树,m次查询。查询路径上k小值。

注释:$1\le n,m\le 10^5$。

想法:好像更博顺序有一些问题... ...

root[i]表示以i为根的主席树根

对于查询的两个点x,y,我们只需要查询

root[x]+root[y]-root[lca(x,y)]-root[fa[lca(x,y)]]的主席树即可。

具体地,每个节点的权值线段树维护的是当前结点到根的路径上这些点权值的权值线段树。

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
int ans,tot,cnt,anc,n,m,q,x,y,z,d[100010],v[100010],h[100010],l[3000010],r[3000010],to[200010],head[100010],next[200010],sum[3000010],root[100010],f[100010][20];
map<int,int>b;
void add(int x,int y)
{
    tot++;
    next[tot]=head[x];
    head[x]=tot;
    to[tot]=y;
}
int lca(int x,int y)
{
    if(d[x]<d[y])
    {
        swap(x,y);
    }
    int dep=d[x]-d[y];
    for(int i=0;i<=19;i++)
    {
        if((dep&(1<<i))!=0)
        {
            x=f[x][i];
        }
    }
    if(x==y)
    {
        return x;
    }
    for(int i=19;i>=0;i--)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}
int updata(int pre,int L,int R,int k)
{
	int mid=(L+R)>>1;
    int rt=++cnt;
    l[rt]=l[pre];
    r[rt]=r[pre];
    sum[rt]=sum[pre]+1;
    if(L==R)
    {
        return rt;
    }
    else
    {
        if(k<=mid)
        {
            l[rt]=updata(l[pre],L,mid,k);
        }
        else
        {
            r[rt]=updata(r[pre],mid+1,R,k);
        }
    }
    return rt;
}
int query(int x,int y,int anc,int fa,int L,int R,int k)
{
	int mid=(L+R)>>1;
    if(L==R)
    {
        return b[L];
    }
    int num=sum[l[x]]+sum[l[y]]-sum[l[anc]]-sum[l[fa]];
    if(num>=k)
    {
        return query(l[x],l[y],l[anc],l[fa],L,mid,k);
    }
    else
    {
        return query(r[x],r[y],r[anc],r[fa],mid+1,R,k-num);
    }
}
void dfs(int x,int fa)
{
    d[x]=d[fa]+1;
    int k=lower_bound(h+1,h+1+m,v[x])-h;
    b[k]=v[x];
    root[x]=updata(root[fa],1,n,k);
    for(int i=1;i<=19;i++)
    {
        f[x][i]=f[f[x][i-1]][i-1];
    }
    for(int i=head[x];i;i=next[i])
    {
        if(to[i]!=fa)
        {
            f[to[i]][0]=x;
            dfs(to[i],x);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&v[i]);
        h[i]=v[i];
    }
    sort(h+1,h+1+n);
    m=unique(h+1,h+1+n)-h-1;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        x=x^ans;
        anc=lca(x,y);
        ans=query(root[x],root[y],root[anc],root[f[anc][0]],1,n,z);
        printf("%d\n",ans);
    }
}

小结:在树上的主席树就是nb... ...

posted @ 2018-07-24 21:41  JZYshuraK_彧  阅读(219)  评论(0编辑  收藏  举报