[bzoj2588]Count on a tree

传送门

乍看像是树剖,但是树剖的话就不能用权值线段树,不能权值线段树求区间第k小就只能树套树,诶静态的当然主席树啦!!
树剖也不需要了诶,好像只需要dfs建主席树就好了,这样建出来的主席树\(rt[i]\),所包含的就是根到\(i\)节点路径上的点,对于查询\((x,y)\)就可以差分解决了;
也就是查询\((root,x)+(root,y)-(root,lca(x,y))-(root,f[lca(x,y)])\)
差分部分具体可以看代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
map<int,int>mp;
const int maxn=1e5+1;
int cnt,n,m,lastans,id,rt[maxn],d[maxn],tot,ff[maxn],ls[maxn*20],rs[maxn*20],size[maxn*20],h[maxn],nxt[maxn*2],pre[maxn*2],dep[maxn],f[maxn][20],w[maxn];
#define rg register
void update(int x){size[x]=size[ls[x]]+size[rs[x]];}
void change(int x,int &k,int l,int r,int a)
{
    k=++id,ls[k]=ls[x],rs[k]=rs[x],size[k]=size[x];
    if(l==r){size[k]++;return ;}
    int mid=(l+r)>>1;
    if(a<=mid)change(ls[x],ls[k],l,mid,a);
    else change(rs[x],rs[k],mid+1,r,a);
    update(k);
}
void add(int x,int y)
{
    pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt;
    pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt;
}
void dfs(int x,int fa)
{
    for(rg int i=1;i<20;i++)
    {
        if((1<<i)>dep[x])break;
        f[x][i]=f[f[x][i-1]][i-1];
    }
    change(rt[fa],rt[x],1,tot,mp[d[x]]);
    for(rg int i=h[x];i;i=nxt[i])if(pre[i]!=fa)f[pre[i]][0]=x,dep[pre[i]]=dep[x]+1,dfs(pre[i],x);
}
int lca(int x,int y)
{
    if(dep[x]>dep[y])swap(x,y);
    int poor=dep[y]-dep[x];
    for(rg int i=19;i>=0;i--)if(poor&(1<<i))y=f[y][i];
    for(rg int i=19;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return x==y?x:f[y][0];
}
int get(int a,int b,int c,int d,int l,int r,int k)
{
    if(l==r)return w[l];
    int mid=(l+r)>>1,now=size[ls[a]]+size[ls[b]]-size[ls[c]]-size[ls[d]];
    if(k<=now)return get(ls[a],ls[b],ls[c],ls[d],l,mid,k);
    else return get(rs[a],rs[b],rs[c],rs[d],mid+1,r,k-now);
}
int main()
{
    read(n),read(m);
    for(rg int i=1;i<=n;i++)read(d[i]),ff[i]=d[i];
    sort(ff+1,ff+n+1);
    for(rg int i=1;i<=n;i++)if(!mp[ff[i]])mp[ff[i]]=++tot,w[tot]=ff[i];
    for(rg int i=1,x,y,z;i<n;i++)read(x),read(y),add(x,y);
    dfs(1,0);
    for(rg int i=1,x,y,z,fa;i<=m;i++)
    {
        read(x),read(y),read(z),x^=lastans;fa=lca(x,y);
        printf("%d\n",lastans=get(rt[x],rt[y],rt[fa],rt[f[fa][0]],1,tot,z));
    }
}
posted @ 2019-01-11 16:33  蒟蒻--lichenxi  阅读(84)  评论(0编辑  收藏  举报