spoj cot Count on a tree (主席树)

题意:

思路:

    我们根据dfs顺序建立主席树。求树上第k大,对于u到v的一条路径,我们用u的树+v的树,很明显lca(u,v)多算了一次,fa[lca(u,v)]多算了两次,所以用u的树+v的树-lca(u,v)的树-fa[lca(u,v)]的树即可

错误及反思:

代码:

#include<bits/stdc++.h>
using namespace std;
#define lson l,m
#define rson m+1,r
const int N  = 100100;
int sum[N*20],ls[N*20],rs[N*20],n,m,val[N],id[N],cnt=0,root[N];
vector<int> son[N],v;
int to[N][25],depth[N];

int getid(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}

int init(int l,int r){
    int rt=++cnt;
    sum[rt]=0,ls[rt]=rt,rs[rt]=rt;
    int m=(l+r)/2;
    if(l!=r){
        ls[rt]=init(lson);
        rs[rt]=init(rson);
    }
    return rt;
}

void dfs(int now,int fa,int dep){
    to[now][0]=fa;
    depth[now]=dep;
    for(int i=0;i<son[now].size();i++)
        if(son[now][i]!=fa)
            dfs(son[now][i],now,dep+1);
}

void initlca(){
    for(int i=1;i<20;i++)
        for(int j=0;j<=n;j++)
            to[j][i]=to[to[j][i-1]][i-1];
}

int lca(int a,int b){
    if(depth[a]>depth[b])
        swap(a,b);
    for(int i=19;i>=0;i--)
        if(depth[to[b][i]]>=depth[a])
            b=to[b][i];
    if(a==b) return a;
    for(int i=19;i>=0;i--){
        if(to[a][i]!=to[b][i]){
            a=to[a][i];
            b=to[b][i];
        }
    }
    return to[a][0];
}

int update(int pre,int x,int l, int r){
    int rt=(++cnt);
    ls[rt]=ls[pre], rs[rt]=rs[pre], sum[rt]=sum[pre]+1;
    if(l!=r){
        int m=(l+r)>>1;
        if(x<=m) ls[rt]=update(ls[pre], x, lson);
        else rs[rt]=update(rs[pre], x, rson);
    }
    return rt;
}

void build(int now,int fa){
    root[now]=update(root[fa],getid(val[now]),1,v.size());
    for(int i=0;i<son[now].size();i++)
        if(son[now][i]!=fa)
            build(son[now][i],now);
}

int query(int u,int v,int lc,int flc,int k,int l,int r){
    if(l==r) return l;
    int m=(l+r)/2;
    int num=sum[ls[u]]+sum[ls[v]]-sum[ls[lc]]-sum[ls[flc]];
    if(num>=k)
        return query(ls[u],ls[v],ls[lc],ls[flc],k,lson);
    return query(rs[u],rs[v],rs[lc],rs[flc],k-num,rson);

}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&val[i]);
        v.push_back(val[i]);
    }
    v.push_back(0);
    sort(v.begin(),v.end()),v.erase(unique(v.begin(),v.end()),v.end());
    for(int i=0,u,v;i<n-1;i++){
        scanf("%d%d",&u,&v);
        son[u].push_back(v);
        son[v].push_back(u);
    }
    son[0].push_back(1);
    son[1].push_back(0);
    root[0]=init(1,v.size());
    dfs(0,0,1);
    initlca();
    build(1,0);
    while(m--){
        int u,vv,k,lc,flc;
        scanf("%d%d%d",&u,&vv,&k);
        lc=lca(u,vv);
        flc=to[lc][0];
        printf("%d\n",v[query(root[u],root[vv],root[lc],root[flc],k,1,v.size())-1]);
    }
}

猜你喜欢

转载自blog.csdn.net/roll_keyboard/article/details/80555983
今日推荐