这是计蒜客noi模拟赛的day1第二题,现在写完了,发一波题解。
先上题目:敌对势力
这一题先想到的是暴力暴力出奇迹 ,后面只得了30分,然后后面老师说是lca我当场懵逼 ,为什么?原来是看错了,我以为是一个图,这当然不可以用lca,废话 ,后面才看到是无根树,眼瞎害死人 。
讲正事,看到无根树我们首先看看可不可以转成有根树,而这一题刚好可以,因为题目无特殊要求,所以我们可以随便选个点作为根,我们优先选择1,选择的原则是能简单就简单,不要给自己找麻烦。转换成有根树后我们再说说怎么用lca。
题目给我们两条路,我们画图自己算了一下后发现好像有一个特点:如果两条路有交点的话,那么这两条路中必有一条的lca在另一条上,为什么?因为这是一个树。后面我们自己证明了一下,还真是,至于证明因为简单和难以阐述(是你自己不会说吧 )所以就大家自己在草稿纸上画画图,都能算出来,证明讲完了就是求lca了,在此我们用倍增求lca,倍增应该不用讲吧,所以我们直接用了。求出lca,我们就要去check了,我们暴力把路径分为两条,分别是从lca到两个端点。这样我们直接暴力枚举check就好了。
上代码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
int Next[200100],head[200100],ver[200100],size=0,d[100100],f[100100][30],t;
queue <int> q;//倍增常规队列
void add(int x,int y)//邻接表操作
{size++;Next[size]=head[x];head[x]=size;ver[size]=y;return ;
}
int lca(int x,int y)//倍增查询
{if(d[x]>d[y])swap(x,y);for(int i=t;i>=0;i--)if(d[f[y][i]]>=d[x])y=f[y][i];if(x==y)return x;for(int i=t;i>=0;i--){if(f[x][i]!=f[y][i]){x=f[x][i];y=f[y][i];}}return f[x][0];
}
void bfs()//倍增预处理
{q.push(1);d[1]=1;while(q.size()){int x=q.front();q.pop();for(int i=head[x];i;i=Next[i]){int y=ver[i];if(d[y])continue;d[y]=d[x]+1;f[y][0]=x;for(int j=1;j<=t;j++)f[y][j]=f[f[y][j-1]][j-1];q.push(y);}}return ;
}
bool check(int fa,int x,int y)//暴力查找
{if(x==fa)return true;while(x!=y){x=f[x][0];if(fa==x)return true;}return false;
}
int main()
{int n,m;memset(d,0,sizeof(d));scanf("%d %d",&n,&m);t=(int)((log(n)/log(2))+1);for(int i=1;i<n;i++)//读入 {int u,v;scanf("%d %d",&u,&v);add(u,v);add(v,u);}bfs();for(int i=1;i<=m;i++)//询问 {int a,b,c,e,fa1,fa2;scanf("%d %d %d %d",&a,&b,&c,&e);fa1=lca(a,b);//找到两条路的lca fa2=lca(c,e);if(d[fa2]>d[fa1])//减个枝,因为我们发现一定是深度大的在另一条路上 {if(check(fa2,a,fa1) || check(fa2,b,fa1))//有碰到为真printf("NO \n");else printf("YES \n");}else {if(check(fa1,c,fa2) || check(fa1,e,fa2))//有碰到为真printf("NO \n");else printf("YES \n");}}return 0;}

一提交发现只有70分,为什么?方法错了吗,其实不是,只是后面check的时候错了,我们的check的时间复杂度是O(n),看起来很小,可是题目承受不了,所以我们要换一下,通过画图我们发现如果有一个点在路径上那么这个点分别和路径的两个端点的lca一定有一个是它本身,这个很好证明,就大家自己画画图证明一下,这样我们就可以降到(logn),这样就ojbk了,下面上代码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
int Next[200100],head[200100],ver[200100],size=0,d[100100],f[100100][30],t;
queue <int> q;
void add(int x,int y)//邻接表尝龟操作
{size++;Next[size]=head[x];head[x]=size;ver[size]=y;return ;
}
int lca(int x,int y)//倍增lca查询
{if(d[x]>d[y])swap(x,y);for(int i=t;i>=0;i--)if(d[f[y][i]]>=d[x])y=f[y][i];if(x==y)return x;for(int i=t;i>=0;i--){if(f[x][i]!=f[y][i]){x=f[x][i];y=f[y][i];}}return f[x][0];
}
void bfs()//预处理一波
{q.push(1);d[1]=1;while(q.size()){int x=q.front();q.pop();for(int i=head[x];i;i=Next[i]){int y=ver[i];if(d[y])continue;d[y]=d[x]+1;f[y][0]=x;for(int j=1;j<=t;j++)f[y][j]=f[f[y][j-1]][j-1];q.push(y);}}return ;
}
int main()
{int n,m;memset(d,0,sizeof(d));scanf("%d %d",&n,&m);t=(int)((log(n)/log(2))+1);for(int i=1;i<n;i++){int u,v;scanf("%d %d",&u,&v);add(u,v);add(v,u);}bfs();for(int i=1;i<=m;i++){int a,b,c,e,fa1,fa2;scanf("%d %d %d %d",&a,&b,&c,&e);fa1=lca(a,b);fa2=lca(c,e);if(d[fa2]<d[fa1])//稍稍减个枝 {if(lca(fa1,c)==fa1 || lca(fa1,e)==fa1)//有碰到为真printf("NO \n");else printf("YES \n");}else{if(lca(fa2,a)==fa2 || lca(fa2,b)==fa2)//有碰到为真printf("NO \n");else printf("YES \n");}}return 0;
}

这样这一题就AC了,希望这篇题解对大家有帮助,也希望大家可以动手打打代码,不要直接复制。

lca题目 敌对势力 题解相关推荐

  1. 2021/4/24团队设计天梯赛L1题目集及题解

    2021/4/24团队设计天梯赛L1题目集及题解: 以下题解都是通过PTA测试的,大致保证正确性: 查看题目戳此::PTA题目集 L1题目集 L1-01 人与神(5分) L1-02 #两小时学完C语言 ...

  2. 链表基础概念与经典题目(Leetcode题解-Python语言)

    所谓链表,就是由链节点元素组成的表,那什么是链节点呢?直接上定义: class ListNode:def __init__(self, val=0, next=None):self.val = val ...

  3. 二分查找基础概念与经典题目(Leetcode题解-Python语言)二分索引型

    二分查找的定义如下(引自Wiki): 在计算机科学中,二分查找算法(英语:binary search algorithm),也称折半搜索算法(英语:half-interval search algor ...

  4. 两数、三数、四数之和相关题目(Leetcode题解-Python语言)

    作为 Leetcode 的第一题,两数之和自然是知名度最高的,从两数之和出发也有不少的衍生题目,下面就让我们好好地解决它们. 1. 两数之和 class Solution:def twoSum(sel ...

  5. 字符串经典题目(Leetcode题解-Python语言)

    344. 反转字符串 class Solution:def reverseString(self, s: List[str]) -> None:"""Do not ...

  6. 队列的基础概念与经典题目(Leetcode题解-Python语言)

    队列是先入先出(后入后出)的数据结构,常用操作就 push 和 popleft,Python中用列表中的 pop(0) 或者 collection.deque的 popleft() 都可以. 普通队列 ...

  7. 在数组中找重复数、只出现一次的数或丢失数的题目(Leetcode题解-Python语言)

    在一维数组中的考察中,最常见的就是找出数组中的重复数.只出现一次的数或者丢失(消失)数等等. 一般来说,首先想到的就是用哈希表(集合)来记录出现过的数,基本所有的题都可以用集合来做,而技巧性在于有时可 ...

  8. 二叉树序列化与反序列化相关题目(Leetcode题解-Python语言)

    297. 二叉树的序列化与反序列化(剑指 Offer 37. 序列化二叉树)(剑指 Offer II 048. 序列化与反序列化二叉树) class Codec:def serialize(self, ...

  9. 高度平衡的二叉搜索树基础概念与经典题目(Leetcode题解-Python语言)

    高度平衡的二叉搜索树(平衡二叉树),定义见此Leetbook.简单来说,就是基于相同节点值构建出来的二叉搜索树中高度最小的,即为平衡二叉树(不唯一).有 N 个节点的平衡二叉搜索树,它的高度是 log ...

最新文章

  1. 时隔两年,EfficientNet v2来了!更快,更小,更强!
  2. 搜索插件(django-haystack)
  3. Proxy + Reflect 实现 响应的数据变化
  4. 计算机英语课程背景,专家讲座第十五讲:信息化背景下高质量大学英语课程建设与教学设计...
  5. HttpServletResponse.getWriter().print乱码,request.getHeader乱码,解决方法
  6. 飞鸽传书下载2013
  7. c语言 printf_C语言(4) 屏幕输出指令printf
  8. 【老孙随笔】 神秘的茶馆
  9. iphone尺寸_巨额罚款无法“阻挡”,iPhone 12真机现已开箱,一睹为快!|iphone|手机|包装盒...
  10. python数据采集卡_高速数据采集卡在雷达信号的采集与分析中的应用笔记
  11. win10系统去除桌面图标小箭头
  12. 2021金山wps校招(前端)
  13. Statistic模块管理统计功能,用于提供应用内统计的能力,支持统计和分析用户属性和用户行为数据。通过plus.statistic可获取统计管理对象
  14. 切换IP及DNS上网一键脚本设置
  15. 关于百分位数(percentile)
  16. 华为+android+root权限获取root,[Android]如何获取华为手机的root权限
  17. 安装两个虚拟机只为验证一个猜测,结果不出所料(Unity | deviceUniqueIdentifier | 设备ID相同)
  18. AxureRP和Markman新手入门心得
  19. [转]通过研究视线轨迹改良设计
  20. 阿里云ACP考试模拟试题(2)

热门文章

  1. 新手使用MySQL Workbench以及用MyEclipse jsp 连接的几个坑
  2. tp5类的属性不存在_tp5
  3. 蓝牙耳机哪个品牌性价比高?适合圣诞送礼的高性价比蓝牙耳机推荐
  4. 高校战“疫”网络安全分享赛
  5. excel导入导出工具包 Qexcel
  6. 北京市国资委监管企业名单
  7. C3P0数据库连接池的解析
  8. 百万现金奖励,FlyAI实时竞赛等你来战
  9. 计算动态优先级 -- effective_prio()
  10. 25年精细创新,打印让生活更美好