约会 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国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社 ...
随机推荐
- pip Fatal error in launcher: Unable to create process using '""'
如果你装了python2.7, python3.5, 在两个版本的兼容问题上折腾很久了, 通过修改环境变量, 能够出现下面的界面, 恭喜你, 暂时解决了一些问题, 哈哈
- 通过wscript运行的JS脚本,如何引入另一个JS文件
链接: https://helloacm.com/include-external-files-in-vbscriptjscript-wsh/ 代码示例: function Include(jsFil ...
- cento7忘记root密码怎么办
1.首先开启系统,一直按 e 键 进入编辑选项 2.光标下移,在UTF-8行这一段修改两处,首相找到ro改为rw,即只读改为可读写权限:然后在这段的尾部加入 init=/bin/sh 3.此时按住Ct ...
- python3.5以后venv创建/激活/退出虚拟环境
1.创建虚拟环境 $ python3 -m venv <环境名称> 2.激活虚拟环境 $ source <环境名称>/bin/activate 3.关闭虚拟环境 $ deact ...
- swagger-ui升级swagger-bootstrap-ui界面好看到起飞
如果项目已经集成了swagger,只需要在pom.xml添加,如果你的项目没有集成swagger,自行百度或看最下方的链接 swagger-bootstrap-ui是Swagger的前端UI实现,目的 ...
- Cocos2d-X多线程(1) 在cocos2d-x中使用多线程
教科书上说:进程是资源分配的最小单位,线程是CPU调度的最小单位. 进程是程序在计算机上的一次执行活动.直观的讲就是会产生一个pid. int main() { //业务逻辑代码 re ...
- CSRF token的原理
参考: http://www.cnblogs.com/zhaof/p/6281482.html 简介 django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.cs ...
- python目录和引用关系
这是我的项目目录 像这样引用没有直接画横线 但是运行时会报错:找不到 typeidea.typeidea.文件路径 图片拖出来看更清晰 后期补充: 解决方案: 如:右击:typeidea----- ...
- websocket服务器推送 (node+express+vue+socket)
简介: 此项目需要懂一点node.express 功能: 1.前端用户登录,查看服务端推送的消息,用户只能在一个地方登录,也就是单点登录 2.服务端首先登录,上传需要推送的信息文本,后台读取文本后,存 ...
- python 并发编程 多线程 多线程实现并发的套接字通信
进程内会生成一个主线程,让主线程执行server函数,server函数核心是accept(),让主线程干accept的工作, 建立连接,每建立一个连接应该执行通信函数 每建立一个连接就是生成一个子线程 ...