标签:insert splay algo std 算法 ems lap 深度 turn
题意
有一棵有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 }
【HDU 6031]】 Innumerable Ancestors
标签:insert splay algo std 算法 ems lap 深度 turn
原文地址:https://www.cnblogs.com/LQLlulu/p/8955220.html