1. 程式人生 > >【HDU 6031]】 Innumerable Ancestors

【HDU 6031]】 Innumerable Ancestors

click sin opened dot -s clas class ret return

題意

有一棵有n個結點的樹,這裏有m個詢問,每個詢問給出兩個非空的結點集合A和B,有些結點可能同時在這兩個集合當中。你需要從A和B中分別選擇一個節點x和y(可以是同一個結點)你的目標是使LCA(x,y)的深度最大。n,m<=100000

分析

LCA算法每次查詢的復雜度都是logn的,如果每個查詢都枚舉兩個集合,那麽均攤的時間復雜度是n^2logn(好像··大概··是吧??

聽說這個題可以通過給兩個集合排序爆過去????為啥我失敗了?姿勢不對嗎?

這個題的標準解法是二分+LCA(倍增預處理)

對於每次查詢,我們二分最大深度。然後怎麽寫check呢?把集合A裏面的,深度為這個二分出來的值的這個點,加入一個set。然後枚舉集合B,如果B裏面這個深度的祖先在這個set裏面,那麽就返回正確。

技術分享圖片
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <vector>
  6 #include <queue>
  7 #include <set>
  8 
  9 using namespace std;
 10 const int maxn=100000+100;
 11 vector<int>G[maxn];
12 int n,m,k1,k2; 13 int f[maxn][20],d[maxn],A[maxn],B[maxn]; 14 void bfs(){ 15 queue<int>q; 16 memset(d,0,sizeof(d)); 17 memset(f,0,sizeof(f)); 18 q.push(1);d[1]=1; 19 while(!q.empty()){ 20 int u=q.front();q.pop(); 21 for(int i=0;i<G[u].size();i++){
22 int v=G[u][i]; 23 if(d[v])continue; 24 d[v]=d[u]+1; 25 f[v][0]=u; 26 for(int j=1;j<=19;j++){ 27 f[v][j]=f[f[v][j-1]][j-1]; 28 } 29 q.push(v); 30 } 31 } 32 return ; 33 } 34 int lca(int x,int y){ 35 if(d[x]>d[y])swap(x,y); 36 for(int i=19;i>=0;i--) 37 if(d[f[y][i]]>=d[x])y=f[y][i]; 38 if(x==y)return x; 39 for(int i=19;i>=0;i--) 40 if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; 41 return f[x][0]; 42 } 43 int query(int u,int fa){ 44 if(fa==0)return u; 45 for(int i=20;i>=0;i--){ 46 if(fa>=(1<<i)){ 47 u=f[u][i]; 48 fa-=(1<<i); 49 } 50 } 51 return u; 52 } 53 bool check(int deep){ 54 set<int>S; 55 for(int i=1;i<=k1;i++){ 56 if(deep>d[A[i]])continue; 57 int res=query(A[i],d[A[i]]-deep); 58 S.insert(res); 59 } 60 for(int i=1;i<=k2;i++){ 61 if(deep>d[B[i]])continue; 62 int res=query(B[i],d[B[i]]-deep); 63 if(S.count(res))return true; 64 } 65 return false; 66 } 67 int main(){ 68 while(scanf("%d%d",&n,&m)!=EOF){ 69 for(int i=1;i<=n;i++)G[i].clear(); 70 for(int i=1;i<n;i++){ 71 int a,b; 72 scanf("%d%d",&a,&b); 73 G[a].push_back(b); 74 G[b].push_back(a); 75 } 76 bfs(); 77 for(int i=1;i<=m;i++){ 78 int L,R,mid; 79 scanf("%d",&k1); 80 R=1; 81 for(int j=1;j<=k1;j++){ 82 scanf("%d",&A[j]); 83 R=max(R,d[A[j]]); 84 } 85 scanf("%d",&k2); 86 for(int j=1;j<=k2;j++) 87 scanf("%d",&B[j]); 88 L=1; 89 while(L+1<R){ 90 mid=L+(R-L)/2; 91 if(check(mid)){ 92 L=mid; 93 }else{ 94 R=mid-1; 95 } 96 } 97 if(check(R)) 98 printf("%d\n",R); 99 else 100 printf("%d\n",L); 101 } 102 } 103 return 0; 104 }
View Code

【HDU 6031]】 Innumerable Ancestors