热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

POI2012约会Rendezvous

题目描述给定一个有nnn个顶点的有向图,每个顶点有且仅有一条出边。每次询问给出两个顶点aia_ia​i​​和bib_ib​i​​,求满足以下条件的xix_ix​i​​和yiy_iy


题目描述

给定一个有 nnn 个顶点的有向图,每个顶点有且仅有一条出边。每次询问给出两个顶点 aia_ia​i​​ 和 bib_ib​i​​,求满足以下条件的 xix_ix​i​​ 和 yiy_iy​i​​:



  • 从顶点 aia_ia​i​​ 沿出边走 xix_ix​i​​ 步与从顶点 bib_ib​i​​ 沿出边走 yiy_iy​i​​ 步到达的顶点相同。

  • max(xi,yi)i​​,y​i​​) 最小。

  • 满足以上条件的情况下 min(xi,yi)i​​,y​i​​) 最小。

  • 如果以上条件没有给出一个唯一的解,则还需要满足 xi≥yii​​≥y​i​​.

如果不存在这样的 xi,yi,输出 -1 -1 ,i​​ 和 yiy_iy​i​​,则 xi=yi=−1x_i = y_i = -1x​i​​=y​i​​=−1.



输入格式

第一行两个正整数 n 和 k(1≤n≤500 000,1≤k≤500 000),表示顶点数和询问个数。

接下来一行 n 个正整数,第 iii 个数表示 iii 号顶点出边指向的顶点。

接下来 k 行表示询问,每行两个整数i​​ 和 bib_ib​i​​.



输出格式

对每组询问输出两个整数 xi,yi,i​​ 和 yiy_iy​i​​.



样例


样例输入

12 5
4 3 5 5 1 1 12 12 9 9 7 1
7 2
8 11
1 2
9 10
10 5

 


样例输出

2 3
1 2
2 2
0 1
-1 -1


数据范围与提示

对于 40% 的数据,n≤2000,k≤2000.

对于 100%100\%100% 的数据,1≤n≤500 000,1≤k≤500 000


   有向有环非联通图通常没什么素质。这题就是这样一个基环森林。。。。。首先要写一个对的LCA然后,可以用并查集来记录是否是一张图的,如果不是一张图上的直接-1 -1。在一张图上,用tarjan找到环(当然你有别的骚方法也没毛病),在环上的一圈点都有自己的子树,dfs的时候记录s[x]为x所在的子树,如果询问中两点在同一子树,直接LCA。如果不在,先找lca(x,s[x]),lca(y,s[y]);再找环上s[x]到s[y]的距离(我是通过选定环上任意一点开始dfs,然后记录每一点dep值,dep值的差和环的size-差是两种路径,根据题意优先级判断。然后就结束了

  PS:(网站loj.ac上有这个题数据,不要问我怎么知道的)


#include
#include
#include
#include
#include
using namespace std;
const int N=500020;
int fr[N],s[N],size[N],stack[N],q[N],c[N],b[N],d[N],low[N],du[N],a[N],dfn[N],tp[N],pt[N],fa[N][20],num,cnt,kt,top,n,k,tt;
bool v[N],vs[N],ins[N];
struct node{int fr,to,pr;}mo[N];
struct qe{int a,b;};
int rd()
{
char cc=getchar();
int s=0,w=1;
while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
return s*w;
}
bool cmp(int x,int y)
{
return du[x]>du[y];
}
void add(int x,int y)
{
mo[++tt].fr=x;
mo[tt].to=y;
mo[tt].pr=fr[x];
fr[x]=tt;du[x]++;
}
int find(int x)
{
if(x!=pt[x]) pt[x]=find(pt[x]);
return pt[x];
}
void merge(int x,int y)
{
x=find(x);y=find(y);
if(x!=y) pt[y]=x;
}
bool jud(int x,int y)
{
x=find(x);y=find(y);
return x==y;
}
void tarjan(int x)
{
low[x]=dfn[x]=++num;
stack[++top]=x;ins[x]=1;
for(int i=fr[x];i;i=mo[i].pr)
{
int y=mo[i].to;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(ins[y]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x])
{
int y,s=0;++cnt;
int tmp=find(stack[top]);
do{
y=stack[top--];

size[cnt]++;
c[y]=cnt;
if(size[cnt]>1) b[tmp]=cnt,tp[tmp]=y;
ins[y]=0;
}while(x!=y);
}
}
void dfs(int x,int str)
{
v[x]=1;s[x]=str;
for(int i=1;i<=18;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=fr[x];i;i=mo[i].pr)
{
int to=mo[i].to;
if(v[to])continue;
fa[to][0]=x,d[to]=d[x]+1;
//cout< if(c[x]!=c[to]) dfs(to,str);
else dfs(to,to);
}
}
qe lca(int x,int y)
{
int ans1=0,ans2=0;
qe ans;
if(d[x] for(int i=18;~i;i--)
if(d[fa[x][i]]>=d[y]) x=fa[x][i],ans1+=(1< ans.a=ans1,ans.b=0;
if(x==y) return ans;
for(int i=18;~i;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],ans1+=(1< ans.a=ans1+1,ans.b=ans2+1;
return ans;
}
int main()
{
//freopen("ran3c.in","r",stdin);
//freopen("ran3c.ans","w",stdout);
n=rd();k=rd();
int x,y,tmp,rt;
for(int i=1;i<=n;i++) pt[i]=i,a[i]=i;
for(int i=1;i<=n;i++)
{
x=rd();
merge(x,i);
if(x==i) continue;
add(x,i);
}
for(int i=1;i<=n;i++) if(!dfn[i]) d[i]=1,tarjan(i);
for(int i=1;i<=n;i++) if(!vs[find(i)]) q[++kt]=find(i);
for(int i=1;i<=kt;i++) if(!v[q[i]]) d[q[i]]=1,dfs(q[i],q[i]);
//for(int i=1;i<=n;i++) printf("%d ",s[i]);
for(int i=1;i<=k;i++)
{
x=rd();y=rd();
if(!jud(x,y)) printf("-1 -1\n");
else
{
tmp=find(x);
if(s[x]==s[y])
{
qe te=lca(x,y);
if(d[x]>d[y])printf("%d %d\n",te.a,te.b);
else printf("%d %d\n",te.b,te.a);
}
else
{
int ans1=lca(x,s[x]).a,ans2=lca(y,s[y]).a,tmp1,tmp2;
x=s[x];y=s[y];
if(d[x] else tmp1=d[x]-d[y],tmp2=size[b[tmp]]-tmp1;
//cout< //for(int i=fr[93];i;i=mo[i].pr) cout<<1<<" ";
if(max(ans1+tmp1,ans2) else if(max(ans1+tmp1,ans2)>max(ans1,ans2+tmp2)) printf("%d %d\n",ans1,ans2+tmp2);
else
{
if(min(ans1+tmp1,ans2) else
{
if(min(ans1+tmp1,ans2)>min(ans1,ans2+tmp2)) printf("%d %d\n",ans1,ans2+tmp2);
else
{
if(ans1+tmp1>=ans2) printf("%d %d\n",ans1+tmp1,ans2);
else printf("%d %d\n",ans1,ans2+tmp2);
}
}
}
}
}
}
}
/*
g++ 1.cpp -o 1
./1
12 5
4 3 5 5 1 1 12 12 9 9 7 1
7 2
8 11
1 2
9 10
10 5
*/
View Code

 


推荐阅读
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
author-avatar
突然丶丶想你
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有