SPOJ-COT Count on a tree Find the k-th smallest point on a path on the tree (LCA+chairman tree)

https://vjudge.net/problem/SPOJ-COT


Idea: With 1 as the root, a new chairperson tree is opened in a linear sequence similar to the original board. Here, a new chairperson tree is opened according to the order of the figure. A tree represents the prefix relationship from this point to the root node.

Then find the k-th point on the path and use the prefix relationship with LCA.

But here and the previous https://blog.csdn.net/zstuyyyyccccbbbb/article/details/109882553 there is a common repetitive part about LCA point rights.

Here pass LL sum=tree[tree[pre].l].sum+tree[tree[suf].l].sum-tree[tree[LCA].l].sum-tree[tree[LCAfather].l ].sum; to achieve the purpose of maintaining the right to the lca point.

Note on the code: query(root[u],root[v],root[LCA],root[FALCA],1,cnt,k); the first thing thrown in is root[], which is the chairman tree corresponding to this point Root node.

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+1000;
typedef long long LL;
typedef pair<LL,LL>P;
///主席树部分
LL nodeid=0;
struct Tree{
    LL l,r,sum;
}tree[maxn*20];
LL a[maxn],b[maxn],cnt=0;
LL root[maxn];
LL update(LL pre,LL l,LL r,LL x){
    LL rt=++nodeid;
    tree[rt].l=tree[pre].l;
    tree[rt].r=tree[pre].r;
    tree[rt].sum=tree[pre].sum+1;
    LL mid=(l+r)>>1;
    if(l<r){
        if(x<=mid){
            tree[rt].l=update(tree[pre].l,l,mid,x);
        }
        else tree[rt].r=update(tree[pre].r,mid+1,r,x);
    }
    return rt;
}
LL query(LL pre,LL suf,LL LCA,LL LCAfather,LL l,LL r,LL k){
    if(l==r) return l;
    LL sum=tree[tree[pre].l].sum+tree[tree[suf].l].sum-tree[tree[LCA].l].sum-tree[tree[LCAfather].l].sum;
 ///   debug(l);debug(r);
    LL mid=(l+r)>>1;

    if(sum>=k){///查第k小
        return query(tree[pre].l,tree[suf].l,tree[LCA].l,tree[LCAfather].l,l,mid,k);
    }
    else return query(tree[pre].r,tree[suf].r,tree[LCA].r,tree[LCAfather].r,mid+1,r,k-sum);
}

///树剖部分求LCA
LL siz[maxn],son[maxn],top[maxn],fa[maxn],dep[maxn];
vector<LL>g[maxn];
void predfs(LL u,LL father){
    siz[u]=1;dep[u]=dep[father]+1;
    fa[u]=father;
    for(LL i=0;i<g[u].size();i++){
        LL v=g[u][i];
        if(v==father) continue;
        LL x=lower_bound(b+1,b+cnt+1,a[v])-b;
        root[v]=update(root[u],1,cnt,x);
        predfs(v,u);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]]){
            son[u]=v;
        }
    }
}
void dfs(LL u,LL topx){
    top[u]=topx;
    if(!son[u]) return;
    dfs(son[u],topx);
    for(LL i=0;i<g[u].size();i++){
        LL v=g[u][i];
        if(v==fa[u]||v==son[u]) continue;
        dfs(v,v);
    }
}
LL getLCA(LL u,LL v){
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        u=fa[top[u]];
    }
    if(dep[u]>dep[v]) swap(u,v);
    return u;
}
LL path_query(LL u,LL v,LL k){
   ///if(dep[u]>dep[v]) swap(u,v);
   LL LCA=getLCA(u,v);
  /// debug(LCA);
   LL FALCA=fa[LCA];
   debug(FALCA);
  /// cout<<"fuck"<<endl;
   debug(cnt);
   return query(root[u],root[v],root[LCA],root[FALCA],1,cnt,k);
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n,m;cin>>n>>m;
  for(LL i=1;i<=n;i++){
    cin>>a[i];
    b[i]=a[i];
  }
  sort(b+1,b+1+n);
  cnt=unique(b+1,b+1+n)-b-1;
  for(LL i=1;i<n;i++){
    LL u,v;cin>>u>>v;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  LL x=lower_bound(b+1,b+1+cnt,a[1])-b;
  root[1]=update(root[0],1,cnt,x);
  predfs(1,0);
  dfs(1,1);
 /// cout<<"fuck"<<endl;
///  shuchu(1,1,cnt);
  while(m--){
    LL u,v,k;cin>>u>>v>>k;
    ///cout<<path_query(u,v,k)<<endl;
    cout<<b[path_query(u,v,k)]<<endl;
  }
return 0;
}

 

Guess you like

Origin blog.csdn.net/zstuyyyyccccbbbb/article/details/110136440