约会 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国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社 ...
随机推荐
- 如何使用Loadrunner Controller 监控服务器的系统资源
(1)保证装有loadrunner Controller的控制机和被监控的目标机(服务器)之间能够ping通,在同一个网段内,保证两台机器用administrator登陆. (2)Win + R, s ...
- Linux环境Nginx安装
开始前,请确认gcc g++开发类库是否装好,默认已经安装. ububtu平台编译环境可以使用以下指令 apt-get install build-essential apt-get install ...
- java:容器/集合Collection(List(ArrayList,LinkedList,Vector),Set(HashSet(LinkedHashSet),TreeSet))
/** * Collection接口 不唯一,无序 * 常用的方法: * add(Object e) 确保此 collection 包含指定的元素(可选操作). * size():获取集合中元素的个 ...
- java 接口default的判断规则
1.前言 jdk1.8中新增加了default关键字,就是在接口中可以增加默认实现. 因为改动接口所有的实现类都要改动,所以增加了default关键字后不需要修改其他类,默认给所有实现类增加了方法. ...
- 启动elasticsearch-head显示集群健康值:未连接
ES启动后,进行es header访问的话,使用localhost:9100会显示集群健康值未连接 2种情况(均为windows10环境下): 1:未在elasticsearch-6.8.0\conf ...
- LeetCode.985-查询后偶数的总和(Sum of Even Numbers After Queries)
这是悦乐书的第370次更新,第398篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第232题(顺位题号是985).有一个整数数组A和一个查询数组queries. 对于第i ...
- C++ 多文件编译简述:头文件、链接性、声明与定义
目录 Commen Sense 头文件 链接性 static 与链接性控制 extern 与外部链接性 Reference Commen Sense C++ 在编译时对每个翻译单元(Translati ...
- Akka系列(十):Akka集群之Akka Cluster
前言........... 上一篇文章我们讲了Akka Remote,理解了Akka中的远程通信,其实Akka Cluster可以看成Akka Remote的扩展,由原来的两点变成由多点组成的通信网络 ...
- PTA(Basic Level)1061.判断题
判断题的评判很简单,本题就要求你写个简单的程序帮助老师判题并统计学生们判断题的得分. 输入格式: 输入在第一行给出两个不超过 100 的正整数 N 和 M,分别是学生人数和判断题数量.第二行给出 M ...
- Boruvka
大概是这样的:一开始图中有\(n\)个连通块,每次操作我们选出各个连通块连出去的最短的边(如果有相同边权的边的话可以把序号作为第二关键字),然后把这些边加入最小生成树. 最坏的情况下每次操作都会让当前 ...