BZOJ2791/POI2012 Rendezvous
来源:互联网 发布:数据库模糊查询sql语句 编辑:程序博客网 时间:2024/06/05 03:36
Task
给定一个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。
n,q<=500,000.
Solution
根据题目的条件可以建出一棵基环外向树,也就是下图的结构.
可以看做一个环和以环上各个节点为根的树.那么对于(x,y)就有以下几种可能:
1.x,y在不同联通块中,无解.
2.x,y在同一棵树中,例如(a,b).那么两点之间的最短路径是确定的,就是它们分别走向LCA的步数.现在问题就转化成了求LCA了.
3.x,y在不同的树中,例如(d,a).那么它们相遇的路径有两种可能:
a->c,d->c或a->e,d->e,只要记录每个节点所在的树 的根节点编号和在环上的位置即可.
Code
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int M=500005;const int S=20;int dep[M],ec=0,fa[M],n,q,A[M],head[M],id[M],par[M][S],sz[M],B[M];//一千万 int on[M];inline void rd(int &res){ res=0;char c; while(c=getchar(),c<48); do res=(res<<1)+(res<<3)+(c^48); while(c=getchar(),c>=48);}inline void print(int x){ if(!x)return ; print(x/10); putchar((x%10)^48);}inline void sc(int x){ if(x<0){x=-x;putchar('-');} print(x); if(!x)putchar('0');}struct node{ int to,nex;}e[M];int get(int x){ if(fa[x]!=x)return fa[x]=get(fa[x]); return fa[x];}void Add_edge(int a,int b){ e[ec]=(node){b,head[a]}; head[a]=ec++;}void dfs(int p,int x,int d){ dep[x]=d; id[x]=p; for(int i=head[x];~i;i=e[i].nex){ dfs(p,e[i].to,d+1); }}void pt(int a,int b){ sc(a);putchar(' '); sc(b);putchar('\n');}int lca(int a,int b){ if(dep[a]<dep[b])swap(a,b); if(b==id[a])return b; int i,step=dep[a]-dep[b]; for(i=S-1;i>=0;i--){ if(step&(1<<i))a=par[a][i]; } if(a==b)return a; for(i=S-1;i>=0;i--){ if(par[a][i]!=par[b][i])a=par[a][i],b=par[b][i]; } return par[a][0];}int main(){ int i,j,k,a,b,c; memset(head,-1,sizeof(head)); scanf("%d %d",&n,&q); for(i=1;i<=n;i++)fa[i]=i; for(i=1;i<=n;i++){ rd(A[i]); int x=get(A[i]); if(x==i){//find a loop B[x]=id[x]=x;sz[x]=1; on[x]=1;x=A[i]; while(x!=i){//找到环 B[x]=i; on[x]=++sz[i]; x=A[x]; } } else fa[i]=x; par[i][0]=A[i]; } for(i=1;i<=n;i++){ if(!on[i])Add_edge(A[i],i); } for(i=1;i<=n;i++){ if(on[i])dfs(i,i,1);//i是环上的节点,以i为根遍历树 } for(j=1;j<S;j++){ for(i=1;i<=n;i++) par[i][j]=par[par[i][j-1]][j-1]; } while(q--){ rd(a);rd(b); if(B[id[a]]!=B[id[b]]){ pt(-1,-1); continue; } if(id[a]==id[b]){ int c=lca(a,b); pt(dep[a]-dep[c],dep[b]-dep[c]); continue; } int c=dep[a]-dep[id[a]],d=dep[b]-dep[id[b]]; int mx1,mx2,siz=sz[B[id[a]]],step=on[id[b]]-on[id[a]];//表示从a走到b if(step<0)step+=siz; mx1=max(c+step,d),mx2=max(c,d+siz-step); if(mx1<mx2)pt(c+step,d); else if(mx2<mx1)pt(c,d+siz-step); else { int mn1=c+step+d-mx1,mn2=c+d+siz-step-mx2; if(mn1>mn2)pt(c,d+siz-step); else pt(c+step,d); } } return 0;}
0 0
- BZOJ2791: [Poi2012]Rendezvous
- BZOJ2791/POI2012 Rendezvous
- BZOJ2791: [Poi2012]Rendezvous
- [BZOJ 2791]POI2012 Rendezvous
- BZOJ 2791 Poi2012 Rendezvous 倍增LCA
- bzoj 2791 [Poi2012]Rendezvous 倍增lca 基环树
- TIBCO Rendezvous 概念
- Loadrunner集合点Rendezvous知识
- Loadrunner集合点Rendezvous知识
- RVD (Rendezvous daemon)
- Loadrunner集合点Rendezvous知识
- Loadrunner集合点Rendezvous知识
- Loadrunner集合点Rendezvous知识
- Loadrunner:集合点(Rendezvous)
- POI2012题解
- [Poi2012]Festival
- TIBCO Rendezvous — 技术介绍
- TIBCO Rendezvous — 技术介绍
- Java JNI开发时常用数据类型与C++中数据类型转换
- 如何通过设计验证让SoC芯片流片成功
- 2. Add Two Numbers
- Android产品研发(二十二)-->Android实用调试技巧
- chrome devTools--Source面板的小功能
- BZOJ2791/POI2012 Rendezvous
- 第2课 矩阵消元
- 一些系统事件的手动触发方法
- 使用VC6.0开发COM组件 - 傻瓜式,不讲理论,只讲实例
- 组合式继承深度剖析
- 互联网汽车信息娱乐系统基础框架
- @Autowired与@Resource的区别
- 使用表单上传文件的过程及需要考虑的问题
- ListView数据更新后,自动滚动到底部