码迷,mamicode.com
首页 > 其他好文 > 详细

【HDU 6031]】 Innumerable Ancestors

时间:2018-04-26 23:34:40      阅读:222      评论:0      收藏:0      [点我收藏+]

标签: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 }
View Code

 

【HDU 6031]】 Innumerable Ancestors

标签:insert   splay   algo   std   算法   ems   lap   深度   turn   

原文地址:https://www.cnblogs.com/LQLlulu/p/8955220.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!