2791: [Poi2012]Rendezvous

Time Limit: 25 Sec  Memory Limit: 128 MB
Submit: 259  Solved: 160
[Submit][Status][Discuss]

Description

给定一个n个顶点的有向图,每个顶点有且仅有一条出边。

对于顶点i,记它的出边为(i, a[i])。

再给出q组询问,每组询问由两个顶点a、b组成,要求输出满足下面条件的x、y:

1. 从顶点a沿着出边走x步和从顶点b沿着出边走y步后到达的顶点相同。

2. 在满足条件1的情况下max(x,y)最小。

3. 在满足条件1和2的情况下min(x,y)最小。

4. 在满足条件1、2和3的情况下x>=y。

如果不存在满足条件1的x、y,输出-1 -1。

Input

第一行两个正整数n和q (n,q<=500,000)。

第二行n个正整数a[1],a[2],...,a[n] (a[i]<=n)。

下面q行,每行两个正整数a,b (a,b<=n),表示一组询问。

Output

输出q行,每行两个整数。

Sample Input

12 5

4 3 5 5 1 1 12 12 9 9 7 1

7 2

8 11

1 2

9 10

10 5


Sample Output

2 3

1 2

2 2

0 1

-1 -1


HINT

Source

[Submit][Status][Discuss]

HOME
Back


题解

我是很久没有好好写一篇题解了。

首先分析题意,是要沿着出边跳到相同的节点,说明要求的是lca。

然后说一下基环树的套路:

  1. 树上倍增可以照常写,注意使用的条件就行了。
  2. 一遍拓扑排序把环找出来,这时候连通且未标记的肯定都在同一个环内。
  3. 以环上任意节点为起点开始做一个环标号,环长度前缀和,还有环总长。具体可以直接用出边跳。
  4. 把不在环上的点的出边反向用来建树,以环为根处理深度,环根标号

这样询问时的处理套路:

  1. 不在同一连通块内,即环根标号对应节点的环标号不同,那么lca不存在。
  2. 在同一棵树内,即环根标号相同,直接树上lca解决。
  3. 这题我们主要解决的情况——在同一连通块内,但是不在同一棵树内,即环根标号对应节点的环标号相同,但环根标号不同。

    x,y肯定要调到环上,然后分为两种情况,x,y分别跳。用预处理的3解决。

这样询问时间复杂度可以做到\(O(1)\),不过这题我的简便写法是\(O(\log n)\)的。总时间复杂度\(((n+m)\log n)\)

#include<bits/stdc++.h>
#define co const
#define il inline
#define rg register
template<class T>T read(){
rg T data=0,w=1;rg char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
return data*w;
}
template<class T>T read(T&x){
return x=read<T>();
}
typedef long long ll;
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second co int N=5e5+1;
int n,m,t,f[N][20],deg[N];
int pos[N],cnt,len[N],s[N];
int d[N],id[N];
vector<int> e[N];
queue<int> q; int lca(int x,int y){
if(d[x]>d[y]) swap(x,y);
for(int i=19;i>=0;--i)
if(d[f[y][i]]>=d[x]) y=f[y][i];
if(x==y) return x;
for(int i=19;i>=0;--i)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
pii cmp(co pii&a,co pii&b){
if(max(a.x,a.y)<max(b.x,b.y)) return a;
if(max(a.x,a.y)>max(b.x,b.y)) return b;
if(min(a.x,a.y)<min(b.x,b.y)) return a;
if(min(a.x,a.y)>min(b.x,b.y)) return b;
return a.x>=a.y?a:b;
}
int main(){
read(n),read(m);
for(int i=1;i<=n;++i) ++deg[read(f[i][0])];
// prework
t=log(n)/log(2);
for(int i=1;i<=t;++i)
for(int x=1;x<=n;++x) f[x][i]=f[f[x][i-1]][i-1];
// topsort
for(int i=1;i<=n;++i)if(!deg[i]) q.push(i);
while(q.size()){
int x=q.front();q.pop();
if(!--deg[f[x][0]]) q.push(f[x][0]);
}
// circle
for(int i=1;i<=n;++i)if(deg[i]&&!pos[i]){
++cnt;
for(int j=i;!pos[j];j=f[j][0])
pos[j]=cnt,s[j]=++len[cnt];
}
// bfs
for(int i=1;i<=n;++i){
if(pos[i]) id[i]=i,q.push(i);
else e[f[i][0]].push_back(i);
}
while(q.size()){
int x=q.front();q.pop();
for(unsigned i=0;i<e[x].size();++i){
int y=e[x][i];
d[y]=d[x]+1,id[y]=id[x];
q.push(y);
}
}
while(m--){
int x=read<int>(),y=read<int>();
if(pos[id[x]]!=pos[id[y]]) puts("-1 -1");
else if(id[x]==id[y]){
int p=lca(x,y);
printf("%d %d\n",d[x]-d[p],d[y]-d[p]);
}
else{
pii a,b;
int sx=s[id[x]],sy=s[id[y]],now=len[pos[id[x]]];
a.x=d[x]+(sy-sx+now)%now,a.y=d[y];
b.x=d[x],b.y=d[y]+(sx-sy+now)%now;
pii ans=cmp(a,b);
printf("%d %d\n",ans.x,ans.y);
}
}
return 0;
}

LG3533 [POI2012]RAN-Rendezvous的更多相关文章

  1. Solution -「基环树」做题记录

    写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...

  2. [BZOJ2791][Poi2012]Rendezvous

    2791: [Poi2012]Rendezvous Time Limit: 25 Sec  Memory Limit: 128 MBSubmit: 95  Solved: 71[Submit][Sta ...

  3. 【BZOJ2791】[Poi2012]Rendezvous 倍增

    [BZOJ2791][Poi2012]Rendezvous Description 给定一个n个顶点的有向图,每个顶点有且仅有一条出边.对于顶点i,记它的出边为(i, a[i]).再给出q组询问,每组 ...

  4. 【BZOJ 2791】 2791: [Poi2012]Rendezvous (环套树、树链剖分LCA)

    2791: [Poi2012]Rendezvous Description 给定一个n个顶点的有向图,每个顶点有且仅有一条出边.对于顶点i,记它的出边为(i, a[i]).再给出q组询问,每组询问由两 ...

  5. 「POI2012」约会 Rendezvous

    #2691. 「POI2012」约会 Rendezvous 这题我简直不想说什么了,什么素质,卡常数…… “每个顶点有且仅有一条出边”,所以是一道基环树的题,首先tarjan缩点,在缩完点后的图上求a ...

  6. bzoj 2791 [Poi2012]Rendezvous 基环森林

    题目大意 给定一个n个顶点的有向图,每个顶点有且仅有一条出边. 对于顶点i,记它的出边为(i, a[i]). 再给出q组询问,每组询问由两个顶点a.b组成,要求输出满足下面条件的x.y: 从顶点a沿着 ...

  7. [BZOJ2791]:[Poi2012]Rendezvous(塔尖+倍增LCA)

    题目传送门 题目描述 给定一个有n个顶点的有向图,每个顶点有且仅有一条出边.每次询问给出两个顶点${a}_{i}$和${b}_{i}$​​,求满足以下条件的${x}_{i}$和${y}_{i}$:   ...

  8. [Poi2012]Rendezvous

    题目描述 给定一个n个顶点的有向图,每个顶点有且仅有一条出边. 对于顶点i,记它的出边为(i, a[i]). 再给出q组询问,每组询问由两个顶点a.b组成,要求输出满足下面条件的x.y: 从顶点a沿着 ...

  9. POI2012题解

    POI2012题解 这次的完整的\(17\)道题哟. [BZOJ2788][Poi2012]Festival 很显然可以差分约束建图.这里问的是变量最多有多少种不同的取值. 我们知道,在同一个强连通分 ...

随机推荐

  1. 【BZOJ2119】股市的预测 后缀数组+分块

    [BZOJ2119]股市的预测 Description 墨墨的妈妈热爱炒股,她要求墨墨为她编写一个软件,预测某只股票未来的走势.股票折线图是研究股票的必备工具,它通过一张时间与股票的价位的函数图像清晰 ...

  2. Stacks of Flapjacks(栈)

     Stacks of Flapjacks  Background Stacks and Queues are often considered the bread and butter of data ...

  3. 打包合并多个dll

    复杂项目中会引用大量的第三方dll文件,为了便于管理会尝试把相关打包合并成一个dll文件. 推荐使用ILMerge,如需使用网上自行下载. 使用方法: cd 安装目录 ILmerge /target: ...

  4. MySQL登陆数据库

    下面是几种登陆到MySql数据库的登陆方式代码 1mysql -u root -ppassword 2.mysql -u root -p Enter password:password3.mysql ...

  5. Card Collector(期望+min-max容斥)

    Card Collector(期望+min-max容斥) Card Collector woc居然在毫不知情的情况下写出一个min-max容斥 题意 买一包方便面有几率附赠一张卡,有\(n\)种卡,每 ...

  6. LOJ#10117. 「一本通 4.1 练习 2」简单题

    LOJ#10117. 「一本通 4.1 练习 2」简单题 题目描述 题目来源:$CQOI 2006$ 有一个$n$个元素的数组,每个元素初始均为$0$.有$m$条指令,要么让其中一段连续序列数字反转— ...

  7. Django redis2 列表 和其他操作

    列表的操作 List操作,redis中的List在在内存中按照一个name对应一个List来存储.如图: lpush插值至列表最左边 lpush(name,values) # 在name对应的list ...

  8. 我的Android进阶之旅------>WindowManager.LayoutParams介绍

    本文转载于: http://hubingforever.blog.163.com/blog/static/171040579201175111031938/ 本文参照自: http://develop ...

  9. 4.对urls.py的解释

    解释: 路由配置文件(URL分发器),它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表.就是以这种方式告诉Django对于每个URL的处理类.Django启动的时候回去加载urls. ...

  10. Filebeat 导入 Elasticsearch 的方法

    Filebeat 导入 Elastaticsearch 的方法 1. 什么是Filebeat?到底是干什么的? Filebeat说实话,就是一个日志监控分发器,类似tail -f这样去监控某个日志,或 ...