[Poi2012]Rendezvous
题目描述
给定一个n个顶点的有向图,每个顶点有且仅有一条出边。
对于顶点i,记它的出边为(i, a[i])。
再给出q组询问,每组询问由两个顶点a、b组成,要求输出满足下面条件的x、y:
从顶点a沿着出边走x步和从顶点b沿着出边走y步后到达的顶点相同。
在满足条件1的情况下max(x,y)最小。
在满足条件1和2的情况下min(x,y)最小。
在满足条件1、2和3的情况下x>=y。如果不存在满足条件1的x、y,输出-1 -1。
输入格式
第一行两个正整数n和q (n,q<=500,000)。
第二行n个正整数a[1],a[2],...,a[n] (a[i]<=n)。
下面q行,每行两个正整数a,b (a,b<=n),表示一组询问。
输出格式
输出q行,每行两个整数。
第一句话就明显地点明了这是一道基环树的题。并且还是一颗内向基环树。
我们考虑每对x,y的情况:
1.x,y不在一棵基环树上。那么输出-1即可。
2.x,y在同一棵子树上。那么答案就是树上距离,用lca求解即可。
3.x,y在同一棵基环树上,但不在同一棵子树上。由于是有向图,我们可以枚举x走过环到y的距离和y走过环到x的距离,根据题目输出答案即可。
具体流程:
1.首先预处理出环。
2.预处理出树上倍增的fa数组和每个点所在的子树、基环树编号,并且准备好要使用的距离的信息。
对于每个询问,在线回答即可。
时间复杂度为O(N+Q) ~ O((N+Q)logN)
*很容易写爆的基环树的题。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define maxn 500010
#define maxm 500010
using namespace std;
struct graph{
struct edge{
int to,next;
edge(){}
edge(const int &_to,const int &_next){ to=_to,next=_next; }
}e[maxn<<1];
int head[maxn],k;
inline void init(){ memset(head,-1,sizeof head); }
inline void add(const int &u,const int &v){ e[k]=edge(v,head[u]),head[u]=k++; }
}a,b;
int id[maxn],stack[maxn],top,col[maxn],cnt,size[maxn];
int fa[maxn][20],root[maxn],dep[maxn];
bool inloop[maxn],vis[maxn],instack[maxn];
int n,m,maxdep;
inline int read(){
register int x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
void dfs_getloop(int u){
stack[++top]=u,instack[u]=vis[u]=true;
for(register int i=a.head[u];~i;i=a.e[i].next){
int v=a.e[i].to;
if(!vis[v]) dfs_getloop(v);
else if(instack[v]){
int w,t=top; cnt++;
do{ w=stack[t--],instack[w]=false,inloop[w]=true,col[w]=cnt,id[w]=++size[cnt]; }while(w!=v);
}
}
instack[u]=false,top--;
}
void dfs_getfa(int u,int rt){
root[u]=rt,col[u]=col[rt];
for(register int i=b.head[u];~i;i=b.e[i].next){
int v=b.e[i].to;
if(inloop[v]||root[v]) continue;
dep[v]=dep[u]+1,fa[v][0]=u;
for(register int i=1;i<=maxdep;i++) fa[v][i]=fa[fa[v][i-1]][i-1];
dfs_getfa(v,rt);
}
}
inline int lca(int u,int v){
if(dep[u]>dep[v]) swap(u,v);
for(register int i=maxdep;i>=0;i--) if(dep[fa[v][i]]>=dep[u]) v=fa[v][i];
if(u==v) return u;
for(register int i=maxdep;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
inline bool cmp(int x1,int y1,int x2,int y2){
if(max(x1,y1)!=max(x2,y2)) return max(x1,y1)<max(x2,y2);
if(min(x1,y1)!=min(x2,y2)) return min(x1,y1)<min(x2,y2);
return x1>=y1;
}
int main(){
a.init(),b.init();
n=read(),m=read();
for(register int i=1;i<=n;i++){
int v=read();
a.add(i,v),b.add(v,i);
}
maxdep=(int)log(n)/log(2)+1;
for(register int i=1;i<=n;i++) if(!vis[i]) dfs_getloop(i);
for(register int i=1;i<=n;i++) if(inloop[i]) dfs_getfa(i,i);
for(register int i=1;i<=m;i++){
int u=read(),v=read();
if(col[u]!=col[v]){ puts("-1 -1"); continue; }
if(root[u]==root[v]){
int w=lca(u,v);
printf("%d %d\n",dep[u]-dep[w],dep[v]-dep[w]);
}else{
int ans1=dep[u],ans2=dep[v];
int dis1=(id[root[u]]-id[root[v]]+size[col[u]])%size[col[u]];
int dis2=(id[root[v]]-id[root[u]]+size[col[v]])%size[col[v]];
if(cmp(ans1+dis1,ans2,ans1,ans2+dis2)) printf("%d %d\n",ans1+dis1,ans2);
else printf("%d %d\n",ans1,ans2+dis2);
}
}
return 0;
}
附上我用来调试的代码(太容易写爆了)
//for(register int i=1;i<=n;i++) if(inloop[i]) printf("%d ",i);puts("");
//for(register int i=1;i<=n;i++) printf("%d ",id[i]);puts("");
//for(register int i=1;i<=n;i++) printf("%d ",col[i]);puts("");
//for(register int i=1;i<=n;i++) printf("%d ",size[col[i]]);puts("");
//for(register int i=1;i<=n;i++) printf("%d ",root[i]);puts("");
//for(register int i=1;i<=n;i++) printf("%d ",dep[i]);puts("");
//for(register int i=1;i<=n;i++) printf("%d ",inloop[i]);puts("");
/*for(register int i=1;i<=n;i++){
for(register int j=0;j<=maxdep;j++) printf("%d ",fa[i][j]);puts("");
}*/
//printf("%d\n",maxdep);
[Poi2012]Rendezvous的更多相关文章
- [BZOJ2791][Poi2012]Rendezvous
2791: [Poi2012]Rendezvous Time Limit: 25 Sec Memory Limit: 128 MBSubmit: 95 Solved: 71[Submit][Sta ...
- 【BZOJ2791】[Poi2012]Rendezvous 倍增
[BZOJ2791][Poi2012]Rendezvous Description 给定一个n个顶点的有向图,每个顶点有且仅有一条出边.对于顶点i,记它的出边为(i, a[i]).再给出q组询问,每组 ...
- 【BZOJ 2791】 2791: [Poi2012]Rendezvous (环套树、树链剖分LCA)
2791: [Poi2012]Rendezvous Description 给定一个n个顶点的有向图,每个顶点有且仅有一条出边.对于顶点i,记它的出边为(i, a[i]).再给出q组询问,每组询问由两 ...
- bzoj 2791 [Poi2012]Rendezvous 基环森林
题目大意 给定一个n个顶点的有向图,每个顶点有且仅有一条出边. 对于顶点i,记它的出边为(i, a[i]). 再给出q组询问,每组询问由两个顶点a.b组成,要求输出满足下面条件的x.y: 从顶点a沿着 ...
- [BZOJ2791]:[Poi2012]Rendezvous(塔尖+倍增LCA)
题目传送门 题目描述 给定一个有n个顶点的有向图,每个顶点有且仅有一条出边.每次询问给出两个顶点${a}_{i}$和${b}_{i}$,求满足以下条件的${x}_{i}$和${y}_{i}$: ...
- POI2012题解
POI2012题解 这次的完整的\(17\)道题哟. [BZOJ2788][Poi2012]Festival 很显然可以差分约束建图.这里问的是变量最多有多少种不同的取值. 我们知道,在同一个强连通分 ...
- LG3533 [POI2012]RAN-Rendezvous
2791: [Poi2012]Rendezvous Time Limit: 25 Sec Memory Limit: 128 MBSubmit: 259 Solved: 160[Submit][S ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- 「POI2012」约会 Rendezvous
#2691. 「POI2012」约会 Rendezvous 这题我简直不想说什么了,什么素质,卡常数…… “每个顶点有且仅有一条出边”,所以是一道基环树的题,首先tarjan缩点,在缩完点后的图上求a ...
随机推荐
- 2020-2021-1 20209307《Linux内核原理与分析》第四周作业
一.Linux内核源代码简介 1.计算机三大法宝 存储程序计算机 函数调用堆栈 中断机制 2.操作系统两把宝剑 中断上下文的切换 进程上下文的切换 3.函数目录 Linux-3.18.6/arch/x ...
- 部署docker镜像仓库及高可用
下载地址: https://github.com/goharbor/harbor/releases 安装harbor服务器: 安装harbor root@harbor-vm1:/usr/loc ...
- 制作3D小汽车游戏(上)
之前一段时间家里和公司的事太多,一直没有时间写博客,最近腾出一段时间,看了一遍官方的examples,收货颇多,想整理一点东西出来,又苦于没有好的东西,three写点东西真是太难了.好吧,今天郭先生就 ...
- Windows系统/office安装与激活
一.Windows安装与激活 1.Windows7/8/10安装 提示: 重装系统时C盘会被格式化,故在重装系统前请先手动将重要资料转移到其他地方: 制作一个大白菜U盘winpe启动盘 查 ...
- 十大经典排序算法最强总结(含Java、Python码实现)
引言 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法.排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面 ...
- MySQL中的模糊查询 like 和 Oracle中的 instr() 函数有同样的查询效果
注:MySQL中的模糊查询 like 和 Oracle中的 instr() 函数有同样的查询效果: 如下所示: MySQL: select * from tableName where name li ...
- laravel 数据库之DB类
// 取回数据表的第一条数据 DB::table('table')->where('key', 'value')->first(); DB::table('table')->firs ...
- Atlas 2.1.0 实践(2)—— 安装Atlas
在完成Atlas编译以后,就可以进行Atlas的安装了.Atlas的安装主要是安装Atlas的Server端,也就Atlas的管理页面,并确保Atlas与Kafka Hbase Solr等组件的集成. ...
- mybatis实现MySQL数据库的增删改查之二
这里直接附上代码: 1 package com.qijian.pojo; 2 3 import org.apache.ibatis.type.Alias; 4 5 6 public class Use ...
- 项目中同一个页面引入不同的jQuery版本的不冲突问题
在写项目的过程中,如果需要使用jQuery时,时长会遇到需要引入不同版本的jQuery,可能上一个负责该项目的人用到的是老版本的jQuery,而你去添加功能时用的是新版本的,这个问题很难避免掉,如果去 ...