
Idiot 的间谍网络
发布日期:2021-05-07 06:54:36
浏览次数:7
分类:原创文章
本文共 2956 字,大约阅读时间需要 9 分钟。
I d i o t 的 间 谍 网 络 Idiot\ 的间谍网络 Idiot 的间谍网络
题目链接:
题目大意
有三种操作:
- 读入: 1 x y 1\ x\ y 1 x y:特工 y y y成为特工 x x x的直接领导。数据保证在此之前特工 x x x没有直接领导;
- 读入: 2 x 2\ x 2 x:特工 x x x策划了一起特别行动,然后上报其直接领导审批,之后其直接领导再上报其直接领导的直接领导审批,以此类推,直到某个特工审批后不再有直接领导;
- 读入: 3 x y 3\ x\ y 3 x y:询问特工 x x x 是否直接策划或审批过第 y y y次特别行动。所有特别行动按发生时间的顺序从 1 1 1开始依次编号。数据保证在询问之前,第 y y y次特别行动已经发生过。(输出 Y E S YES YES或者 N O NO NO)
样例输入
6 122 11 4 13 4 11 3 42 33 4 12 33 4 23 1 13 1 33 1 21 2 4
样例输出
NONOYESYESYESYES
数据范围
对于 30 % 30\% 30% 的数据, n < = 3 ∗ 1 0 3 n <= 3 *10^3 n<=3∗103, m < = 5 ∗ 1 0 3 m <= 5* 10^3 m<=5∗103;
对于 60 % 60\% 60% 的数据, n < = 2 ∗ 1 0 5 n <=2 * 10^5 n<=2∗105, m < = 2 ∗ 1 0 5 m <= 2 * 10^5 m<=2∗105;
额外 20 % 20\% 20% 的数据,保证在任意时刻,整张间谍网络由若干条互不相交的链构成;
对于 100 % 100\% 100% 的数据, n < = 5 ∗ 1 0 5 n <= 5 * 10^5 n<=5∗105, m < = 5 ∗ 1 0 5 m <= 5 * 10^5 m<=5∗105;
C + + C++ C++选手的程序在评测时使用编译选项 − W l ; − − s t a c k = 104857600 -Wl;--stack\ =\ 104857600 −Wl;−−stack = 104857600。
思路
这是一道用到并查集和 d f s dfs dfs的问题。
看 A A A知道 B B B干的第 x x x件事,要满足两个点:
- A A A是 B B B的祖先(或它自己)
- B B B干第 x x x件事时, A A A和 B B B已经连通。(或者说 A A A已经是 B B B的祖先(或它本身))
首先,我们来康康第 1 1 1个要求,这个要求我们可以用 d f s dfs dfs序来实现。
接着,第 2 2 2个要求,可以读入完之后,重新再“读入一遍”。操作 1 1 1就并查集确立祖先,这样子操作 2 2 2的时候就可以看他们的祖先是否相同。(相同就是连通的,否则不连通)
(说的有点乱,看代码可能好点)
这样,我们就可以知道答案了。
代码
#include<cstdio>#include<algorithm>using namespace std;struct note { int to, next;}e[500001];struct read { int what, num, who;}a[500001];int n, m, le[500001], z[500001], x[500001], y[500001], k, kk, kkk, in[500001], out[500001], father[500001];bool fa[500001], ans[500001];bool cmp(read x, read y) { //按询问的任务从前到后排序 return x.what < y.what;}void dfs(int now) { //求出dfs序 in[now] = ++in[0]; for (int i = le[now]; i; i = e[i].next) { dfs(e[i].to); } out[now] = ++out[0];}int find(int now) { //并查集 if (father[now] == now) return now; return father[now] = find(father[now]);}int main() { scanf("%d %d", &n, &m);//读入 for (int i = 1; i <= m; i++) { scanf("%d", &z[i]);//读入 if (z[i] == 1) { scanf("%d %d", &x[i], &y[i]);//读入 e[++k] = (note){ x[i], le[y[i]]}; le[y[i]] = k;//建邻接表 fa[x[i]] = 1;//找出所有根节点 } else if (z[i] == 2) { scanf("%d", &x[i]);//读入 } else if (z[i] == 3) { scanf("%d %d", &x[i], &y[i]);//读入 a[++kk] = (read){ y[i], ++kkk, x[i]};//记录 } } sort(a + 1, a + kk + 1, cmp);//按询问的任务从前到后排序 for (int i = 1; i <= n; i++) { //求出的dfs序,以便确定某个点是否是某一个点的祖先(或它本身) father[i] = i;//乘机初始化并查集 if (!fa[i]) { dfs(i); } } int what_num = 0, what = 1;//初始化 for (int i = 1; i <= m; i++) { if (z[i] == 1) father[find(x[i])] = find(y[i]);//连线 else if (z[i] == 2) { what_num++;//到第几个任务 while (what <= kk && a[what].what <= what_num) { //是否还是那次任务 if (find(a[what].who) == find(x[i]) && in[a[what].who] <= in[x[i]] && out[a[what].who] >= out[x[i]])//判断是否连通,且是否是祖先 ans[a[what].num] = 1;//标记 what++;//到下一个询问 } } } for (int i = 1; i <= kk; i++) if (ans[i]) printf("YES\n");//知道 else printf("NO\n"); //不知道 return 0;}
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2025年03月25日 07时55分42秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
java 多态类型转换
2019-03-04
java ==和equals
2019-03-04
java 接口(Interface)多态特性
2019-03-04
搜集整理随机产生人的姓名的2种方法
2019-03-04
最简单的Socket程序[入门篇]
2019-03-04
VS2005图标默认存放位置
2019-03-04
常用正则表达式
2019-03-04
C#中换行的代码
2019-03-04
用正则表达式过滤多余空格
2019-03-04
XML:采用XHTML和CSS设计可重用可换肤的WEB站点
2019-03-04
U盘“无法识别的USB设备”解决办法
2019-03-04
4-6 在Vue中使用插槽
2019-03-04
十二、 PHP (PDO)操作数据库
2019-03-04
二叉树 简单实现 问题解决
2019-03-04
第2章 可行性研究
2019-03-04
python入门——运算符
2019-03-04
【springmvc】传值的几种方式&&postman接口测试
2019-03-04
泳道图简介
2019-03-04
Tomcat6中web项目部署路径webapps和wtpwebapps的区别
2019-03-04