BZOJ 10628 Luogu 2633

BZOJ 10628 Luogu2633——count on a tree

题意:查询一定区间内第K小的点权。

由于有lastans所以强制在线,这道题就相当于树上的主席树,

树链剖分+主席树,主席树相比普通主席树有一丢丢的改变,

root[i]不再是指向root[i-1],而是指向它在树上的父亲,

维护的序列是它到根节点的这条路径。

所以在求区间第k小时,可以用前缀和的思想加上lca,

val[u]+val[v]-val[lca]-val[fa[lca]],

得出的是lca分别到u和v的这两条路径中每个节点的数出现的次数。

然后用二分思想,跟普通主席树一样,二分直至l==r。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int size[100005]={0},fa[100005]={0},son[100005]={0},top[100005],dep[100005]={0},ls[100005*20],rs[100005*20],val[100005*20],root[100005],sz,v[100005],
head[100005*2]={0},t=0,a[100002]={0},tot=0,real[100005]={0},dfn[100005]={0},num,cnt=0,pai[100005];
struct hh
{int  u,v,next;
}e[200005];
void add(int x,int  y)
{
    t++;
    e[t].u=x;
    e[t].v=y;
    e[t].next=head[x];
    head[x]=t;
}
void dfs(int now,int anc)
{
    
    int i;
    top[now]=anc;
        tot++;
    dfn[now]=tot;
    real[tot]=now;
    if(son[now]==-1) return;
     dfs(son[now],anc);
    for(i=head[now];i!=0;i=e[i].next)
    {
        int v=e[i].v;
        if(v!=fa[now]&&v!=son[now])
        dfs(v,v);
    }
}
void build(int u)
{
    size[u]=1;
    for(int i=head[u];i!=0;i=e[i].next)
    {
        int v=e[i].v;
        if(v!=fa[u])
        {
            dep[v]=dep[u]+1;
            fa[v]=u;
            build(v);
            size[u]=size[u]+size[v];
            if(son[u]==-1||size[v]>size[son[u]])
            son[u]=v;
        }
    }
}
int getlca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
        {
            swap(x,y);
        }
        x=fa[top[x]];
    }
    if(dep[x]<dep[y])
    {
        swap(x,y);
    }
    return y;
}
void insert(int &p,int cmp,int x,int l,int r){
    p=++cnt;ls[p]=ls[cmp];rs[p]=rs[cmp];val[p]=val[cmp]+1;
    if(l!=r){
        int mid=(l+r)/2;
        if(x<=mid){
            insert(ls[p],ls[cmp],x,l,mid);
        }
        else{
            insert(rs[p],rs[cmp],x,mid+1,r);
        }
    }
}
int query(int l,int r,int k){
    int a=l,b=r,c=getlca(a,b),d=fa[c],mid,all;
    a=root[dfn[a]];b=root[dfn[b]];c=root[dfn[c]];d=root[dfn[d]];
     l=1,r=sz;
    while(l<r){
        mid=(l+r)>>1;
        all=val[ls[a]]+val[ls[b]]-val[ls[c]]-val[ls[d]];
        if(all>=k){
            r=mid;a=ls[a];b=ls[b];c=ls[c];d=ls[d];
        }
        else{
            l=mid+1;a=rs[a];b=rs[b];c=rs[c];d=rs[d];k-=all;
        }
    }
    return v[l];
}
void jian(int &p,int l,int r){
    p=++cnt;
    if(l!=r){
        int mid=(l+r)/2;
        jian(ls[p],l,mid);
        jian(rs[p],mid+1,r);
    }
}
int main()
{
int c,b,k,p,i,x,y,s,z,lastans=0;
    scanf("%d%d",&num,&p);
    for(i=0;i<=num*4;i++)
    son[i]=-1;
    for(i=1;i<=num;i++)
    {
        scanf("%d",&a[i]);
    }
    for(i=1;i<=num-1;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dep[1]=1;
    build(1);
    dfs(1,1);
    
    for(i=1;i<=num;i++){
        v[i]=pai[i]=a[i];
    }
     sort(v+1,v+num+1);
    sz=unique(v+1,v+num+1)-v-1;
    jian(root[0],1,sz);
    for(i=1;i<=num;i++){
        pai[i] = lower_bound(v + 1, v + 1 + sz, a[i]) - v;
    }
    for(i=1;i<=num;i++){
        int t=real[i];
        insert(root[i],root[dfn[fa[t]]],pai[t],1,sz);
    }
    while(p--){
        scanf("%d%d%d",&c,&b,&k);
        c=c^lastans;
        lastans=query(c,b,k);
        printf("%d\n",lastans);
    }
    return 0;
}
BZOJ 10628 Luogu 2633

 

 

 

 

posted @ 2018-01-09 20:08  Konnyaku  阅读(208)  评论(1编辑  收藏  举报