【HDU 6031]】 Innumerable Ancestors

本文介绍了一种结合LCA算法与二分搜索解决特定树形结构查询问题的方法。通过对树进行预处理,利用倍增技巧计算最近公共祖先(LCA),并采用二分搜索确定最大深度,实现高效查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

  有一棵有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

 

转载于:https://www.cnblogs.com/LQLlulu/p/8955220.html

内容概要:本文档详细介绍了Analog Devices公司生产的AD8436真均方根-直流(RMS-to-DC)转换器的技术细节及其应用场景。AD8436由三个独立模块构成:轨到轨FET输入放大器、高动态范围均方根计算内核和精密轨到轨输出放大器。该器件不仅体积小巧、功耗低,而且具有广泛的输入电压范围和快速响应特性。文档涵盖了AD8436的工作原理、配置选项、外部组件选择(如电容)、增益调节、单电源供电、电流互感器配置、接地故障检测、三相电源监测等方面的内容。此外,还特别强调了PCB设计注意事项和误差源分析,旨在帮助工程师更好地理解和应用这款高性能的RMS-DC转换器。 适合人群:从事模拟电路设计的专业工程师和技术人员,尤其是那些需要精确测量交流电信号均方根值的应用开发者。 使用场景及目标:①用于工业自动化、医疗设备、电力监控等领域,实现对交流电压或电流的精准测量;②适用于手持式数字万用表及其他便携式仪器仪表,提供高效的单电源解决方案;③在电流互感器配置中,用于检测微小的电流变化,保障电气安全;④应用于三相电力系统监控,优化建立时间和转换精度。 其他说明:为了确保最佳性能,文档推荐使用高质量的电容器件,并给出了详细的PCB布局指导。同时提醒用户关注电介质吸收和泄漏电流等因素对测量准确性的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值