约会 Rendezvous:基环树
提炼:tarjan判环,dfs建树,倍增lca,预处理环两点间距离
我犯的错误:
1.基环树不只有一棵,可以有很多
2.自环不能将其忽略,(对于我的算法)应该将其特殊考虑在算法内
3.代码一定要简洁有力,不能让自己调都恶心
Code
数组含义:
que[N]队列,in_que[N]tarjan判是否入队,dfn[N],low[N],bel[N]点属于的集合
ver[N]根节点的集合编号,to[N],nxt[N],head[N],f[N][20]倍增lca,d[N]深度,bel_rt[N]点属于的树的根
extra[N],Ex[N]特判自环专用,
vector<int>vec[N]tarjan点集合
#include<cstdio>
#include<vector>
const int L=<<|;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
using namespace std;
const int N=5e5+;
int n,k,num_tarjan,num_bian,num_huan,top,
que[N],in_que[N],dfn[N],low[N],bel[N],ver[N],to[N],nxt[N],head[N],f[N][],d[N],bel_rt[N],extra[N],Ex[N];
vector<int>vec[N];
int read(){
int x=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x;
}
void add(int x,int y){if(x==y)extra[++extra[]]=x;
to[++num_bian]=y,nxt[num_bian]=head[x],head[x]=num_bian;
}
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a>b?b:a;}
void tarjan(int x){
dfn[x]=low[x]=++num_tarjan;
que[++top]=x;in_que[x]=;
for(int i=head[x],y;i;i=nxt[i])
if(!dfn[y=to[i]])tarjan(y),low[x]=min(low[x],low[y]);
else if(in_que[y])low[x]=min(low[x],dfn[y]);
if(dfn[x]==low[x]){
num_huan++;
int y;
do{
y=que[top--];
in_que[y]=;
vec[num_huan].push_back(y);
bel[y]=num_huan;
}while(y!=x);
if((int)vec[num_huan].size()>)Ex[++Ex[]]=num_huan;
}
}
void dfs(int x,int depth,int root){
bel_rt[x]=root;
d[x]=depth;
for(int i=head[x],y;i;i=nxt[i]){
if(bel[root]!=bel[y=to[i]]&&!d[y=to[i]]){
f[y][]=x;
for(int j=;j<=;++j)f[y][j]=f[f[y][j-]][j-];
dfs(y,depth+,root);
}
}
}
int get(int x,int y){
if(d[x]<d[y])swap(x,y);
for(int i=;i>=;--i)if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return y;
for(int i=;i>=;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[y][];
}
int main(){
n=read(),k=read();
for(int i=;i<=n;++i)add(read(),i);
for(int i=;i<=n;++i)if(!dfn[i])tarjan(i);
for(int hua=;hua<=Ex[];++hua){int huan=Ex[hua];
for(int i=;i<(int)vec[huan].size();++i){
dfs(vec[huan][i],,vec[huan][i]);
ver[vec[huan][i]]=i+;
}
}
for(int i=;i<=extra[];++i)
if(!d[extra[i]]){
dfs(extra[i],,extra[i]);
ver[extra[i]]=;
}
for(int i=,x,y;i<=k;++i){
x=read(),y=read();
if(bel[bel_rt[x]]!=bel[bel_rt[y]])
printf("-1 -1\n");
else if(bel_rt[x]==bel_rt[y]){
int lca=get(x,y);
printf("%d %d\n",d[x]-d[lca],d[y]-d[lca]);
}
else{
int ai=d[x]-,bi=d[y]-,huan_dis=(int)vec[bel[bel_rt[x]]].size();
int len_b=ver[bel_rt[x]]-ver[bel_rt[y]],len_a;
if(len_b<)len_a=-*len_b,len_b=huan_dis-len_a;
else len_a=huan_dis-len_b;
int Ma=max(ai+len_a,bi),Mb=max(ai,bi+len_b),ma=min(ai+len_a,bi),mb=min(ai,bi+len_b);
//条件一
if(Ma<Mb)
printf("%d %d\n",ai+len_a,bi);
else if(Ma>Mb)
printf("%d %d\n",ai,bi+len_b);
else{
//条件二
if(ma<mb)
printf("%d %d\n",ai+len_a,bi);
else if(ma>mb)
printf("%d %d\n",ai,bi+len_b);
else{
//条件三
if(ai+len_a>=bi)
printf("%d %d\n",ai+len_a,bi);
else
printf("-1 -1\n");
}
}
} }
return ;
}
约会 Rendezvous:基环树的更多相关文章
- 「POI2012」约会 Rendezvous
#2691. 「POI2012」约会 Rendezvous 这题我简直不想说什么了,什么素质,卡常数…… “每个顶点有且仅有一条出边”,所以是一道基环树的题,首先tarjan缩点,在缩完点后的图上求a ...
- Solution -「基环树」做题记录
写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...
- 【BZOJ1791】【IOI2008】【基环树】island(status第一速度)
1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 908 Solved: 159 [Su ...
- 『Island 基环树直径』
Island(IOI 2008) Description 你准备浏览一个公园,该公园由 N 个岛屿组成,当地管理部门从每个岛屿 i 出发向另外一个岛屿建了一座长度为 L_i 的桥,不过桥是可以双向行走 ...
- 【BZOJ4883】 [Lydsy1705月赛]棋盘上的守卫(最小生成树,基环树)
传送门 BZOJ Solution 考虑一下如果把行,列当成点,那么显然这个东西就是一个基环树对吧. 直接按照\(Kruscal\)那样子搞就好了. 代码实现 代码戳这里
- [Codeforces235D]Graph Game——概率与期望+基环树+容斥
题目链接: Codeforces235D 题目大意:给出一棵基环树,并给出如下点分治过程,求点数总遍历次数的期望. 点分治过程: 1.遍历当前联通块内所有点 2.随机选择联通块内一个点删除掉 3.对新 ...
- 洛谷AT2046 Namori(思维,基环树,树形DP)
洛谷题目传送门 神仙思维题还是要写点东西才好. 树 每次操作把相邻且同色的点反色,直接这样思考会发现状态有很强的后效性,没办法考虑转移. 因为树是二分图,所以我们转化模型:在树的奇数层的所有点上都有一 ...
- bzoj1791[IOI2008]Island岛屿(基环树+DP)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1791 题目大意:给你一棵n条边的基环树森林,要你求出所有基环树/树的直径之和.n< ...
- bzoj1040 基环树森林dp
https://www.lydsy.com/JudgeOnline/problem.php?id=1040 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社 ...
随机推荐
- 利用Python处理向不受信任主机发送请求
,HTTP vs HTTPS 超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息.HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器 ...
- 前端必须掌握的 nginx 技能(3)
概述 作为一个前端,我觉得必须要学会使用 nginx 干下面几件事: 代理静态资源 设置反向代理(添加https) 设置缓存 设置 log 部署 smtp 服务 设置 redis 缓存(选) 下面我按 ...
- ping命令介绍
1.ping是TCP/IP协议的一部分,所以只要安装了TCP/IP协议就(无论windows或linux)都可以使用ping命令. 2.ping命令的原理:本机创建一个数据包发送给(ping对象)目标 ...
- 阶段3 2.Spring_01.Spring框架简介_04.spring发展历程
- 分布式任务celery
Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成. 消息中间件 Celery本身不提 ...
- Swift 发送邮件和附件
public function send($filename, array $render = [],$subject = '审核通知') { // Create the Transport $tra ...
- mesh重叠闪烁问题
我用正交摄像机做了2d游戏,但是导出spine动画文件是个mesh ,在游戏里有时会出现2个Mesh来回切换显示顺序问题,导致闪烁 查了下并没有发现什么解决方案 后面突然发现只要将摄像机的Y轴偏移一点 ...
- tail命令 查看文件尾部 输出文件后n行,默认查看文件的后10行
tail命令 查看文件尾部 用于查看日志 默认查看文件的后10行 -n 3 数字 也可以忽略-n 直接加数字 tail 3 查看文件后3行 [root@localhost ~]# tail /e ...
- mac 简洁安装Kafka
Mac 简洁安装Kafka 1.采用homebrew的方式 终端执行命令:brew install kafka 2.修改Kafka服务配置文件server.properties 执行命令: vi /u ...
- 【洛谷p1781】宇宙总统
宇宙总统[题目链接] 关于题目算法,其实就是考排序,那我们直接sort不就好啦,显然不能. 这个题让我重新认识了cmp函数: 以下是我的心路历程: 看到这个题,嗯?这么简单的吗,我直接sort不就好啦 ...