1. 程式人生 > >spoj COT - Count on a tree (樹上第K小 LCA+主席樹)

spoj COT - Count on a tree (樹上第K小 LCA+主席樹)

roo sizeof 過程 mes problems ems name ret bit

鏈接:

https://www.spoj.com/problems/COT/en/

思路:

首先看到求兩點之前的第k小很容易想到用主席樹去寫,但是主席樹處理的是線性結構,而這道題要求的是樹形結構,我們可以用dfs跑出所有點離根的距離-dep[i](根為1,dep[1]也為1)在dfs的過程

中,我們對每一個節點建一棵線段樹,那麽【a,b】就是:root[a] + root[b] - root[lca(a,b)] - root[f[lca(a,b)]]; (因為a-b的路徑上的權值還要算上lca(a,b)這個點,所以不是減2*root[lca(a,b)]);

實現代碼:

#include<bits/stdc++.h>
using
namespace std; #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mid int m = (l + r) >> 1 const int M = 2e5 + 10; int p[M][30],dep[M],head[M],sum[M*20],ls[M*20],rs[M*20],root[M*20]; int cnt1,n,idx,cnt,f[M]; struct node { int to,next; }e[M];
void add(int u,int v){ e[++cnt1].to=v;e[cnt1].next=head[u];head[u]=cnt1; e[++cnt1].to=u;e[cnt1].next=head[v];head[v]=cnt1; } int lca(int a,int b){ if(dep[a] > dep[b]) swap(a,b); int h = dep[b] - dep[a]; //h為高度差 for(int i = 0;(1<<i)<=h;i++){ //(1<<i)&f找到h化為2進制後1的位置,移動到相應的位置
if((1<<i)&h) b = p[b][i]; //比如h = 5(101),先移動2^0祖先,然後再移動2^2祖先 } //cout<<a<<" "<<b<<endl; if(a!=b){ for(int i = 22;i >= 0;i --){ if(p[a][i]!=p[b][i]){ //從最大祖先開始,判斷a,b祖先,是否相同 a = p[a][i]; b = p[b][i]; //如不相同,a,b,同時向上移動2^j } } a = p[a][0]; //這時a的father就是LCA } return a; } void build(int l,int r,int &rt){ rt = ++idx; sum[rt] = 0; if(l == r) return; mid; build(l,m,ls[rt]); build(m+1,r,rs[rt]); } void update(int p,int l,int r,int old,int &rt){ rt = ++idx; ls[rt] = ls[old]; rs[rt] = rs[old]; sum[rt] = sum[old] + 1; if(l == r) return ; mid; if(p <= m) update(p,l,m,ls[old],ls[rt]); else update(p,m+1,r,rs[old],rs[rt]); } int query(int a,int b,int lc,int cl,int l,int r,int k){ if(l == r) return l; mid; int cnt = sum[ls[a]] + sum[ls[b]] - sum[ls[lc]] - sum[ls[cl]]; if(k <= cnt) return query(ls[a],ls[b],ls[lc],ls[cl],l,m,k); else return query(rs[a],rs[b],rs[lc],rs[cl],m+1,r,k-cnt); } int a[M],b[M]; void dfs(int u,int fa){ f[u] = fa; dep[u] = dep[fa] + 1; p[u][0] = fa; for(int i = 1;i < 20;i ++) p[u][i] = p[p[u][i-1]][i-1]; update(a[u],1,cnt,root[fa],root[u]); for(int i = head[u];i!=-1;i = e[i].next){ int v = e[i].to; if(v == fa) continue; dfs(v,u); } } int main() { int m; while(scanf("%d%d",&n,&m)!=EOF){ cnt1 = 0; memset(head,-1,sizeof(head)); memset(dep,0,sizeof(dep)); memset(p,0,sizeof(p)); memset(f,0,sizeof(f)); for(int i = 1; i <= n;i ++){ scanf("%d",&a[i]); b[i] = a[i]; } idx = 0; int l,r,c; sort(b+1,b+n+1); cnt = unique(b+1,b+1+n)-b-1; for(int i = 1;i <= n;i ++) a[i] = lower_bound(b+1,b+cnt+1,a[i]) - b; for(int i = 1;i <= n-1;i ++){ scanf("%d%d",&l,&r); add(l,r); } build(1,cnt,root[0]); dfs(1,0); for(int i = 1;i <= m;i ++){ scanf("%d%d%d",&l,&r,&c); int lc = lca(l,r); int id = query(root[l],root[r],root[lc],root[f[lc]],1,cnt,c); printf("%d\n",b[id]); } } return 0; }

spoj COT - Count on a tree (樹上第K小 LCA+主席樹)