hdu6031 Innumerable Ancestors

hdu6031 Innumerable Ancestors
倍增
题意
给定一张无向图,对于每组询问,给出两个集合 A 与 B
求 lca(x,y) 最深的时候的深度 x属于A y属于B

题解
首先 我们发现答案具有单调性,于是我们就可以二分这个答案 mid
然后 把 a 集合 的 这个深度的祖先 求出来 然后看 与b 集合的这个深度 祖先 是否有交集就行了
用set 判断 是否有交集
用倍增法 快速求出一个点的祖先 求一次 只要 log n

  1 #include <bits/stdc++.h>
  2 #define ll long long
  3 #define cl(a,b) memset(a,b,sizeof(a))
  4 using namespace std ;
  5
  6 const int N = 1e5 + 11 ;
  7 struct Edge{
  8     int to,pre ;
  9 }e[N*2] ;
 10 int n,Q,cnt,k1,k2,ans,l,r ;
 11 int head[N],deep[N],anc[N][21],a[N],b[N] ;
 12
 13 inline int read()
 14 {
 15     int x = 0 , f = 1 ;
 16     char ch = getchar() ;
 17     while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f = -1 ; ch = getchar() ; }
 18     while(ch>=‘0‘&&ch<=‘9‘) { x = x * 10+ch-48 ; ch = getchar() ; }
 19     return x * f ;
 20 }
 21
 22 inline void add(int x,int y)
 23 {
 24     e[++cnt].to = y ;
 25     e[cnt].pre = head[x] ;
 26     head[x] = cnt ;
 27 }
 28
 29 inline void init()
 30 {
 31     cl( head,-1 ) ;
 32     cl( deep,0 ) ;
 33     cl( anc,-1 ) ;
 34     cnt = 0 ;
 35 }
 36
 37 inline void dfs(int u,int fa,int d)
 38 {
 39     deep[ u ] = d ;
 40     for(int i=head[u]; ~i ; i = e[i].pre)
 41     {
 42         int v = e[ i ].to ;
 43         if(v==fa) continue ;
 44         anc[ v ][ 0 ] = u ;
 45         dfs(v,u,d+1) ;
 46     }
 47 }
 48
 49 inline void lca_init()
 50 {
 51     for(int j=1; (1<<j) <= n ; j++)
 52         for( int i=1;i<=n;i++ )
 53             if(anc[i][j-1]!=-1)
 54                 anc[i][j] = anc[anc[i][j-1]][j-1] ;
 55 }
 56
 57 inline int query(int u,int d)
 58 //  返回  u的 第 d 个父亲
 59 {
 60     if( d < 0 ) return -1 ;
 61     if( d==0 ) return u ;
 62     int i ;
 63     for(i=0; (1<<i) <= d ;i++) ;   //  注意 这里有分号相当于 求 log  没有的话 死循环
 64     i-- ;
 65     for( ;i>=0;i--)
 66         if(d-(1<<i) >= 0)
 67         {
 68             d-=(1<<i) ;
 69             u = anc[u][i] ;
 70         }
 71     return u ;
 72 }
 73
 74 inline bool check(int x)
 75 {
 76     set<int>s ;
 77     for(int i=1;i<=k1;i++)
 78     {
 79         int dis = deep[a[ i ]] - x ;
 80         int ret = query(a[ i ],dis) ;
 81         if(ret==-1) continue ;
 82         s.insert(ret) ;
 83     }
 84     for(int i=1;i<=k2;i++)
 85     {
 86         int dis = deep[b[ i ]] - x ;
 87         int ret = query( b[ i ],dis ) ;
 88         if(s.count(ret)) return true ;
 89     }
 90     return false ;
 91 }
 92
 93 int main()
 94 {
 95     while(~scanf("%d%d",&n,&Q))
 96     {
 97         init() ;
 98         int x,y ;
 99         for(int i=1;i<n;i++)
100         {
101             scanf("%d%d",&x,&y) ;
102             add(x,y) ; add(y,x) ;
103         }
104         dfs(1,1,1) ;
105         lca_init() ;
106
107         while(Q--)
108         {
109             scanf("%d",&k1) ;
110             l = 1 ; r = 1 ;
111             for(int i=1;i<=k1;i++)
112                 scanf("%d",&a[ i ]),r = max(r,deep[ a[ i ] ]) ;
113             scanf("%d",&k2) ;
114             for(int i=1;i<=k2;i++)
115                 scanf("%d",&b[ i ]) ;
116             while(l<=r)
117             {
118                 int mid = ( l+r ) >>1 ;
119                 if(check(mid))
120                 {
121                     ans = mid ;
122                     l = mid + 1 ;
123                 }
124                 else
125                     r = mid - 1 ;
126             }
127             printf("%d\n",ans ) ;
128         }
129     }
130
131     return 0 ;
132 }
时间: 2024-08-24 15:45:54

hdu6031 Innumerable Ancestors的相关文章

HDU6031 Innumerable Ancestors 倍增 - 题意详细概括 - 算法详解

题目 查看原题 - HDU6031 Innumerable Ancestors 题目描述 有一棵有n个节点的有根树,根节点为1,其深度为1,现在有m个询问,每次询问给出两个集合A和B,问LCA(x,y)(x∈A,y∈B)的深度最大为多少. 输入描述 有多组数据(数据组数<=5) 对于每一组数据,首先2个数n,m,表示有根树的节点个数和询问个数.然后n-1行,每行2个数a,b表示节点a和节点b之间存在直接的连边:接下去2m行,每两行,分别描述当前询问的集合A和集合B:对于一个集合,用一行来描述,该

hdu 6031 Innumerable Ancestors(LCA+剪枝)

题目链接:hdu 6031 Innumerable Ancestors 题意: 给你一棵n个节点的树,现在有m个询问,每次给你两个点集a,b. 让你从a,b点集中选两个点x,y,使得这两个点的LCA的深度最大. 题解: 标解应该是二分+LCA,不过我试了一下暴力,稍微剪了点枝,就直接过去了. 具体看代码 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 c

hdu 6031 Innumerable Ancestors (虚树 lca)

hdu6031 一棵树(根节点是 1),给出两个集合,集合是 由树上的节点组成的.从两个集合中分别选一个元素,求出他们的 lca,问:lca 的深度最大是多少. 每个询问,两个集合,建虚树,然后dfs一遍,记录子树有没有A点.有没有B点,然后看既有A点又有B点的就更新深度到答案. #include <bits/stdc++.h> using namespace std; const int maxN=100000+10; const int maxM=100000+10; const int

HDU 6031 Innumerable Ancestors

树状数组,倍增,枚举,$dfs$序. 对于每一次的询问,可以枚举$B$集合中的所有点,对于每一个点,在树上二分$LCA$,找到最低的更新答案. 判断是否是$LCA$可以搞个$dfs$序,将$A$集合中所有点标$1$,然后查询子树对应的区间上的区间和. #include <bits/stdc++.h> using namespace std; const int maxn = 100010; int L[maxn],R[maxn]; int c[2*maxn]; int h[maxn]; int

poj 1330 Nearest Common Ancestors

题目连接 http://poj.org/problem?id=1330 Nearest Common Ancestors Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In the figure, each node is labeled with an integer from {1, 2,...,

POJ 1330 Nearest Common Ancestors 倍增算法的LCA

POJ 1330 Nearest Common Ancestors 题意:最近公共祖先的裸题 思路:LCA和ST我们已经很熟悉了,但是这里的f[i][j]却有相似却又不同的含义.f[i][j]表示i节点的第2j个父亲是多少   这个代码不是我的,转自 邝斌博客 1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-9-5 9:45:17 4 File Name :F

Nearest Common Ancestors

Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of

[最近公共祖先] POJ 1330 Nearest Common Ancestors

Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 27316   Accepted: 14052 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In the figure, eac

poj 1330 Nearest Common Ancestors lca 在线rmq

Nearest Common Ancestors Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree.