约会Rendezvous
约会 Rendezvous
题目描述
给定一个有 nnn 个顶点的有向图,每个顶点有且仅有一条出边。每次询问给出两个顶点 aia_iai 和 bib_ibi,求满足以下条件的 xix_ixi 和 yiy_iyi:
- 从顶点 aia_iai 沿出边走 xix_ixi 步与从顶点 bib_ibi 沿出边走 yiy_iyi 步到达的顶点相同。
- max(xi,yi)\max(x_i, y_i)max(xi,yi) 最小。
- 满足以上条件的情况下 min(xi,yi)\min(x_i, y_i)min(xi,yi) 最小。
- 如果以上条件没有给出一个唯一的解,则还需要满足 xi≥yix_i \ge y_ixi≥yi.
如果不存在这样的 xix_ixi 和 yiy_iyi,则 xi=yi=−1x_i = y_i = -1xi=yi=−1.
Q:这题是不是非常简单?
A:毒瘤题。
Q:毒瘤出题人?
A:毒瘤出题人。
Q:是不是比较考验码力,打完想对就能A?
A:毒瘤卡常,你没有一点卡常技巧是过不了的。
Q:我卡卡常就能A了是吗?
A:卡dfs 卡你空间,卡你时间,还特别容易爆栈 你需要特别的姿势!
34个测试点,让你绝望
没有看题解过了的毒瘤题
对于我这个蒟蒻,我调了一天,整整一天,
day1 晚上开始码 没有看题解 大约想了想,好像可以建反边跑lca
然后思考它有什么性质,首先题目里保证了只有一个出边,那么相当与保证了每个图都有一个环
想到可以缩点然后无脑lca 然后又想了想 好像环上比较难处理
day1 晚上码完 得了 38分 稍微改了改 28分
day2 重新理了理思路,想到环上可以预处理,但没想到怎么处理,随手打了个单调队列发现不行
得到了3分的好成绩
#include<bits/stdc++.h>
#define ll long long
#define A 600000
using namespace std;
ll head[A],nxt[A],belong[A],ver[A],tot=0,deep[A],dis[A],t,n,m,dfn[A],sta[A],otp=0,num=0,top=0,low[A],f[A][30],cnt=0,ins[A],sum[A],rt[A],bl[A],zuzong[A],fa[A],bl4[A];
vector <ll> scc[251001];
bool flag[A];
void add(ll x,ll y)
{nxt[++tot]=head[x];ver[tot]=y;head[x]=tot;}
inline ll lca(ll x,ll y)
{
if(deep[x]>deep[y])swap(x,y);
for(ll i=t;i>=0;i--)
{
if(deep[x]==deep[y]) break;
if(deep[x]<=deep[f[y][i]]) y=f[y][i];
}
if(x==y) return x;
for(ll i=t;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
void dfs(ll x,ll st,ll t)
{
deep[x]=st,flag[x]=1;bl4[x]=otp;
for(ll i=head[x];i;i=nxt[i])
{
ll y=ver[i];
if(flag[y]) continue;
rt[y]=t;
dis[y]=dis[x]+1;
f[y][0]=x;
dfs(y,st+1,t);
}
return ;
}
ll read()
{
ll f=1,x=0;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
inline void tarjan(ll x)
{
dfn[x]=low[x]=++num;
sta[++top]=x;ins[x]=1;
for(ll i=head[x];i;i=nxt[i])
{
ll y=ver[i];
if(dfn[y]==0)
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(ins[y])
low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
++cnt;
ll yy=0,cis=0,lu;
while(1)
{
yy=sta[top--];
ins[yy]=0;
cis++;
bl4[yy]=cnt;
if(yy==x)
break;
scc[cnt].push_back(yy);
belong[yy]=-1;
//printf("将%lld赋成-1\n",yy); }
if(cis>1) scc[cnt].push_back(x),belong[x]=-1;
else cnt--;
}
}
void tiaotarjan()
{
cout<<"***"<<endl;
for(ll i=1;i<=cnt;i++)
{
for(ll j=0;j<scc[i].size();j++)
{
cout<<scc[i][j]<<" ";
}
if(scc[i].size()) cout<<endl;
}
cout<<"***"<<endl;
}
void tiaos()
{
}
void work()
{
n=read();m=read();
t=log(n)/log(2)+2;
for(ll i=1;i<=n;i++)
{
ll xx=read();
add(xx,i);
//建反图跑tarjan缩点+lca
}
for(ll i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
top=0;
memset(flag,0,sizeof(flag));
for(ll i=1;i<=cnt;i++)
{
ll size=scc[i].size();otp++;
for(ll ii=0;ii<size;ii++)
{
ll q=scc[i][ii];
for(ll j=head[q];j;j=nxt[j])
{
ll y=ver[j];
if(belong[y]!=-1)
{
rt[y]=q;
dfs(y,1,rt[y]);
f[y][0]=y;
}
}
}
}
for(ll j=1;j<=t;j++)
for(ll i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
/*for(ll i=1;i<=n;i++)
{
if(belong[i]!=-1)
{
printf("i=%lld rt=%lld deep=%lld\n",i,rt[i],deep[i]);
}
}*/
for(ll i=1;i<=m;i++)
{
ll xx=read(),yy=read();
if(bl4[xx]==bl4[yy])
{
ll lc=lca(xx,yy);
//printf("rtx=%lld rty=%lld\n",rt[xx],rt[yy]);
if(rt[xx]==rt[yy])
{
printf("%lld %lld\n",dis[xx]-dis[lc],dis[yy]-dis[lc]);
}
if(rt[xx]!=rt[yy])
{
ll de1=deep[xx],de2=deep[yy];
ll now=bl4[rt[xx]];
ll size=scc[now].size(),ott=0;
bool kais=0;
for(ll ii=0;ii<size*2-1;ii++)
{
if(ii>size)
{
ll j=ii-size;
if(!kais&&(scc[now][ii]==rt[xx]||scc[now][ii]==rt[yy]))
{
kais=1;
}
else if(kais==1)
{
de1<de2?de1++:de2++;
if(scc[now][ii]==rt[xx]||scc[now][ii]==rt[yy])
{
kais=0;
break;
}
}
}
else
{
if(!kais&&(scc[now][ii]==rt[xx]||scc[now][ii]==rt[yy]))
{
kais=1;
}
else if(kais==1)
{
de1<de2?de1++:de2++;
if(scc[now][ii]==rt[xx]||scc[now][ii]==rt[yy])
{
kais=0;
break;
}
}
}
}
printf("%lld %lld\n",de1,de2);
}
}
else
printf("-1 -1\n");
}
}
int main()
{work();}
和同学讨论这个题发现他们也挺艰难的
day2 下午 然后经过艰难的辨认+艰难的手膜得到以下代码
ll lx,ly,bl=belong[ances[x]],rootx=ances[x],rooty=ances[y],disx=deep[x]-deep[rootx],disy=deep[y]-deep[rooty],xy,yx;
for(ll j=0;j<scc[bl].size();j++)
{
if(scc[bl][j]==rootx) lx=j;
if(scc[bl][j]==rooty) ly=j;
}
if(lx<ly)
xy=ly-lx,yx=sz[bl]-(ly-lx);
else
yx=lx-ly,xy=sz[bl]-(lx-ly);
if(max(disx+xy,disy)<max(disx,disy+yx)) printf("%lld %lld\n",disx+xy,disy);
else if(max(disx+xy,disy)>max(disx,disy+yx)) printf("%lld %lld\n",disx,disy+yx);
else
{
if(min(disx+xy,disy)<min(disx,disy+yx)) printf("%lld %lld\n",disx+xy,disy);
else if(min(disx+xy,disy)>min(disx,disy+yx)) printf("%lld %lld\n",disx,disy+yx);
else if(disx+xy>=disy) printf("%lld %lld\n",disx+xy,disy);
else printf("%lld %lld\n",disx,disy+yx);
}
然后TLE了
得知tarjan一定会被卡死
然后改成了dfs(??????)
终于吧MLE整过了之后,就接着TLE
经过几个小时卡常斗争终于A了
#include<bits/stdc++.h>
#define ll int
#define A 510000
const int L=1<<20|1;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
using namespace std;
ll head[A],nxt[A],belong[A],ver[A],tot=0,deep[A],t,n,m,otp=0,num=0,f[A][22],cnt=0,bl[A],ances[A],last,sz[A],v[A],cixu[A],chushi=0;
inline ll find(ll x)
{if(ances[x]==x) return x;return ances[x]=find(ances[x]);}
inline void add(ll x,ll y)
{nxt[++tot]=head[x];ver[tot]=y;head[x]=tot;}
inline ll lca(ll x,ll y)
{
if(deep[x]>deep[y])swap(x,y);
ll w;
for(w=0;(1<<w)<=deep[y];w++);
w--;
for(ll i=w;i>=0;i--)
{
if(deep[x]==deep[y]) break;
if(deep[x]<=deep[f[y][i]]) y=f[y][i];
}
if(x==y) return x;
for(ll i=t;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
inline void dfs(ll x,ll pre)
{
v[x]=++num;
deep[x]=deep[pre]+1;
// printf("%lld \n",deep[x]);
for(ll i=1;(1<<i)<=deep[x];i++)
f[x][i]=f[f[x][i-1]][i-1];
for(ll i=head[x];i;i=nxt[i])
{
ll y=ver[i];
if(v[y]>last)
{
cnt++;
chushi=0;
cixu[x]=++chushi;
sz[cnt]++;
belong[x]=cnt;
ances[x]=x;
for(ll i=x;i!=y;i=f[i][0])
{
cixu[f[i][0]]=++chushi;
belong[f[i][0]]=cnt;
ances[f[i][0]]=f[i][0];
sz[cnt]++;
}
}
else
{
ances[y]=f[y][0]=x
,dfs(y,x);
}
}
}
inline ll Read(){
register ll ret;
register char r;
while(r=getchar(),r<'0'||r>'9');ret=r-48;
while(r=getchar(),r>='0'&&r<='9')ret=ret*10+r-48;
return ret;
}
inline void work()
{
last=0;
n=Read();m=Read();
t=log(n)/log(2)+1;
for(ll i=1;i<=n;i++)
{
ll xx=Read();
add(xx,i);
}
for(ll i=1;i<=n;i++)
if(!v[i])
{
ances[i]=f[i][0]=i;
dfs(i,0);
last=num;
}
for(ll i=1;i<=m;i++)
{
ll x=Read(),y=Read();
if(find(x)!=find(y)&&belong[ances[x]]!=belong[ances[y]]) printf("-1 -1\n");
else
{
if(ances[x]==ances[y])
{
ll lc=lca(x,y);
printf("%d %d\n",deep[x]-deep[lc],deep[y]-deep[lc]);
}
else
{
ll lx,ly,bl=belong[ances[x]],disx=deep[x]-deep[ances[x]],disy=deep[y]-deep[ances[y]],xy,yx;
lx=cixu[ances[x]];ly=cixu[ances[y]];
if(lx<ly)
xy=ly-lx,yx=sz[bl]-(ly-lx);
else
yx=lx-ly,xy=sz[bl]-(lx-ly);
if(max(disx+xy,disy)<max(disx,disy+yx)) printf("%d %d\n",disx+xy,disy);
else if(max(disx+xy,disy)>max(disx,disy+yx)) printf("%d %d\n",disx,disy+yx);
else
{
if(min(disx+xy,disy)<min(disx,disy+yx)) printf("%d %d\n",disx+xy,disy);
else if(min(disx+xy,disy)>min(disx,disy+yx)) printf("%d %d\n",disx,disy+yx);
else if(disx+xy>=disy) printf("%d %d\n",disx+xy,disy);
else printf("%d %d\n",disx,disy+yx);
}
}
}
}
}
main()
{work();}
具体思路
首先我们会发现图中一定存在环而且仅仅存在一个环,可能有多个可分割的图,每个图都有一个环
我们要建反图,这样我们就可以跑lca了
然后我们模拟就完了,对于同一个图上的有如下情况
一.路径不经过环
lca完了
二.路径经过环
我们发现我们缩点时其实是按照一定顺序缩的,事实上是按照逆边顺序缩的
于是我们维护一个类似于dfn序的东西就完了
只在环上维护dfn序,相减就得到了距离
对于不在一个图上的直接-1 -1
#include<bits/stdc++.h>
#define ll int
#define A 510000
const int L=1<<20|1;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
using namespace std;
ll head[A],nxt[A],belong[A],ver[A],tot=0,deep[A],t,n,m,otp=0,num=0,f[A][22],cnt=0,bl[A],ances[A],last,sz[A],v[A],cixu[A],chushi=0;
inline ll find(ll x)
{if(ances[x]==x) return x;return ances[x]=find(ances[x]);}
inline void add(ll x,ll y)
{nxt[++tot]=head[x];ver[tot]=y;head[x]=tot;}
inline ll lca(ll x,ll y)
{
if(deep[x]>deep[y])swap(x,y);
ll w;
for(w=0;(1<<w)<=deep[y];w++);
w--;
for(ll i=w;i>=0;i--)
{
if(deep[x]==deep[y]) break;
if(deep[x]<=deep[f[y][i]]) y=f[y][i];
}
if(x==y) return x;
for(ll i=t;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
inline void dfs(ll x,ll pre)
{
v[x]=++num;
deep[x]=deep[pre]+1;
// printf("%lld \n",deep[x]);
for(ll i=1;(1<<i)<=deep[x];i++)
f[x][i]=f[f[x][i-1]][i-1];
for(ll i=head[x];i;i=nxt[i])
{
ll y=ver[i];
if(v[y]>last)
{
cnt++;
chushi=0;
cixu[x]=++chushi;
sz[cnt]++;
belong[x]=cnt;
ances[x]=x;
for(ll i=x;i!=y;i=f[i][0])
{
cixu[f[i][0]]=++chushi;
belong[f[i][0]]=cnt;
ances[f[i][0]]=f[i][0];
sz[cnt]++;
}
}
else
{
ances[y]=f[y][0]=x
,dfs(y,x);
}
}
}
inline ll Read(){
register ll ret;
register char r;
while(r=getchar(),r<'0'||r>'9');ret=r-48;
while(r=getchar(),r>='0'&&r<='9')ret=ret*10+r-48;
return ret;
}
inline void work()
{
last=0;
n=Read();m=Read();
t=log(n)/log(2)+1;
for(ll i=1;i<=n;i++)
{
ll xx=Read();
add(xx,i);
}
for(ll i=1;i<=n;i++)
if(!v[i])
{
ances[i]=f[i][0]=i;
dfs(i,0);
last=num;
}
for(ll i=1;i<=m;i++)
{
ll x=Read(),y=Read();
if(find(x)!=find(y)&&belong[ances[x]]!=belong[ances[y]]) printf("-1 -1\n");
else
{
if(ances[x]==ances[y])
{
ll lc=lca(x,y);
printf("%d %d\n",deep[x]-deep[lc],deep[y]-deep[lc]);
}
else
{
ll lx,ly,bl=belong[ances[x]],disx=deep[x]-deep[ances[x]],disy=deep[y]-deep[ances[y]],xy,yx;
lx=cixu[ances[x]];ly=cixu[ances[y]];
if(lx<ly)
xy=ly-lx,yx=sz[bl]-(ly-lx);
else
yx=lx-ly,xy=sz[bl]-(lx-ly);
if(max(disx+xy,disy)<max(disx,disy+yx)) printf("%d %d\n",disx+xy,disy);
else if(max(disx+xy,disy)>max(disx,disy+yx)) printf("%d %d\n",disx,disy+yx);
else
{
if(min(disx+xy,disy)<min(disx,disy+yx)) printf("%d %d\n",disx+xy,disy);
else if(min(disx+xy,disy)>min(disx,disy+yx)) printf("%d %d\n",disx,disy+yx);
else if(disx+xy>=disy) printf("%d %d\n",disx+xy,disy);
else printf("%d %d\n",disx,disy+yx);
}
}
}
}
}
main()
{work();}
约会Rendezvous的更多相关文章
- 「POI2012」约会 Rendezvous
#2691. 「POI2012」约会 Rendezvous 这题我简直不想说什么了,什么素质,卡常数…… “每个顶点有且仅有一条出边”,所以是一道基环树的题,首先tarjan缩点,在缩完点后的图上求a ...
- 约会 Rendezvous:基环树
提炼:tarjan判环,dfs建树,倍增lca,预处理环两点间距离 我犯的错误: 1.基环树不只有一棵,可以有很多 2.自环不能将其忽略,(对于我的算法)应该将其特殊考虑在算法内 3.代码一定要简洁有 ...
- 暑期集训日志(Day0~Day5)
章·五:2019-07-15:明月不谙离恨苦,斜光到晓穿朱户 ·昨日小结: 昨天考试又是爆零边缘,除了难过就剩难过了. T1暴力打崩了只拿了5分. T2没给分时间.最后20分钟打了个残码.没仔细观察数 ...
- TensorFlow中的通信机制——Rendezvous(一)本地传输
背景 [作者:DeepLearningStack,阿里巴巴算法工程师,开源TensorFlow Contributor] 在TensorFlow源码中我们经常能看到一个奇怪的词——Rendezvous ...
- [Exchange 2013]创建约会和会议
简介 会议和约会之间的重要区别是,会议有与会者,并且没有约会.约会和会议可以是单实例或属于重复序列,但与会者. 房间或资源中不包括约会,因为它们不需要发送一条消息.在内部,Exchange 使用相同的 ...
- POJ1061青蛙的约会[扩展欧几里得]
青蛙的约会 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 108911 Accepted: 21866 Descript ...
- rqnoj378 约会计划
题目描述 cc是个超级帅哥,口才又好,rp极高(这句话似乎降rp),又非常的幽默,所以很多mm都跟他关系不错.然而,最关键的是,cc能够很好的调解各各妹妹间的关系.mm之间的关系及其复杂,cc必须严格 ...
- poj 1061 青蛙的约会 拓展欧几里得模板
// poj 1061 青蛙的约会 拓展欧几里得模板 // 注意进行exgcd时,保证a,b是正数,最后的答案如果是负数,要加上一个膜 #include <cstdio> #include ...
- PAT 1014. 福尔摩斯的约会 (20)
大侦探福尔摩斯接到一张奇怪的字条:"我们约会吧! 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm".大侦 ...
随机推荐
- (一)RabbitMQ安装与基本配置
[博主使用的环境是阿里云ecs服务器,操作系统为centos] 安装erlang环境 RabbitMQ底层是Erlang语言,因此要先安装erlang环境,就像你要运行Java程序就必须先安装JRE/ ...
- maven简单入门
maven简单部署webapp项目流程及注意事项 maven了解 简介: Maven 是一个项目管理工具,它包含了一个项目对象模型 (POM: Project Object Model),一组标准集合 ...
- 【BUAA软工】Beta阶段设计与计划
一.需求再分析 根据用户反馈,是否发现之前的需求分析有偏差?为什么会出现这种偏差?beta阶段你们是否能真的分析清楚用户需求?如何做到? 根据alpha阶段同学们以及课程组老师和助教的使用反馈,总结起 ...
- 查看报错原因 sshd -t
b for ssh.service failed because the control process exited with error code. See "systemctl sta ...
- 使用nmcli命令配置网络
!!!前言 nmcli是redhat7或者centos7之后的命令该命令可以完成网卡上所有的配置工作,并且可以写入配置文件,永久生效 1.NetworkManager NetworkManager是管 ...
- STM32关于多线程运行的疑问
我有一个疑问,如果 STM32在操作系统环境下 能够一个线程串口中断接收数据 另一个线程 继续进行其他的操作
- python工业互联网应用实战16-前后端分离模式之修改与删除
前一章节介绍了List页面的JQuery技术栈的迁移,这一章节我们花一些篇幅来说说修改/查看页面的技术栈迁移.相对于List的获取数据,修改页面涉及到数据Post提交到后台更新数据库.我们仍旧小步迭代 ...
- MVC、MVP和MVVM的区别
前言 在web1.0时代时,那个时候程序猿还没有前后端之分,更程序员开发的时候,都是要前后端一起写的,前后端的代码都是杂揉在一起,如图下 这种开发模式的话,开发的时候因为不需要和其他人员沟通协作,前后 ...
- Web应用漏洞-NGINX各类请求头缺失对应配置
前言 随着越来越多的网络访问通过WEB界面进行操作,WEB安全已经成为互联网安全的一个热点,基于WEB的攻击广为流行,SQL注入.跨站脚本等WEB应用层漏洞的存在使得网站沦陷.页面篡改.网页挂马等攻击 ...
- 解决Error running 'Tomcat 9': Address localhost:8080 is already in use的问题
在我学习servlet的过程中遇到了tomacat端口8080被占用的情况,所以记录下来,毕竟以后还会碰见这种貌似情况 第一步,打开命令行界面,可快捷键window+R打开输入cmd进入 输入代码:n ...