有两个基础需要掌握:

RMQ,以及LCA。

RMQ:dp[i][j]表示下标从i开始,长度为2^j的一段元素中的最值。则易得状态转移如下:dp[i][j]=max/min(dp[i][j-1],dp[i+2^j-1][j-1];

LCA:最近公共祖先结点的求法:

可先进行一次dfs得到欧拉序列。

比如对,得到序列如下:

节点ver   1 3 1 2 5 7 5 6 5 2 4 2 1

深度R    1 2 1 2 3 4 3 4 3 2 3 2 1

首位first  1 4 2 11 5 8 6   在ver中第一次出现的位置。

则求LCA转化为求区间中深度最小的结点编号。

有,设最大结点数为N,则有

d[i]为结点i到根结点的距离。

//邻接表建图,注意是无向图

int ver[N*],R[N*],first[N],vis[N],d[N];
void dfs(int u,int dep){
vis[u]=;
ver[++tot]=u;
first[u]=tot;
R[tot]=dep;
for(int i=head[u];~i;i=nxt[i]) if(!vis[to[i]]){
int v=to[i];
d[v]=d[u]+cost[i];
dfs(v,dep+);
ver[++tot]=u;R[tot]=dep;
}
}
void ST(int n){
for(int i=;i<=n;i++)
dp[i][]=i;
for(int j=;(<<j)<=n;j++){
for(int i=;i+(<<j)-<=n;i++){
int a=dp[i][j-],b=dp[i+(<<(j-))][j-];
dp[i][j]=R[a]<R[b]?a:b;
}
}
}
int RMQ(int l,int r){
int k=;
while((<<(k+))<=r-l+) k++;
int a=dp[l][k],b=dp[r-(<<k)+][k];
return R[a]<R[b]?a:b;
}
int LCA(int u,int v){
int x=first[u],y=first[v];
if(x>y) swap(x,y);
int res=RMQ(x,y);
return ver[res];
}

则LCA(a,b)得到的就是结点a与b的最近公共祖先结点。

dfs从根结点开始调用。

对题hdu 4297。

题意:有n个房间,每个房间有且只有一条出边指向另一个房间。设两个人在不同的房间,求使得两人相遇所走的最少步数。

解题思路:

此处参考:http://blog.csdn.net/liuzhushiqiang/article/details/9916279

观察图的形态,由于n个点n条边,且每个点出度为1,因此可以认为是一个森林,森林里每棵树都加了一条边形成了一个环,且环是根节点(可以认为缩点后没有出边,即没有父节点)。

显然两点属于不同树的时候不可达;因为图的特殊性,因此没有用强连通做,而是用了并查集判环,也便于给环上每个点标上相对位置。

如果两点在同一颗树上,如果不在根节点的同一分支,那么他们首先要走到环上,然后一个人不动另一个走(至于让a走还是b走要根据两点在环上的相对位置判断优弧和劣弧),如果在同一分支,那就是普通的树上两点间的路径。

如果没有那个环,那就是一个普通的森林中的LCA问题,但是由于缩点了,因此要增加一个虚拟根节点0,把所有环上的点可做是森林中子树的根节点,虚拟根节点向所有树的根节点连边,然后做LCA,如果发现ab两点之间LCA为0,则判断两点是否在一颗子树中,如果不在和不可达,如果在则判优弧和劣弧;如果不等于0,那就等同于一棵树的LCA,可以直接确定两点间的最短距离。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=5e5+,M=;
int tot,ver[*N],R[*N],first[N],vis[N],d[N];
int head[N],to[N*],nxt[N*],cost[N*],cnt;
int n,m,dp[*N][M],F[N],tow[N],cc[N],root[N];
int num,pos[N],len[N];
void ini(){
memset(vis,,sizeof(vis));
memset(head,-,sizeof(head));
memset(d,,sizeof(d));
memset(first,-,sizeof(first));
cnt=tot=;
memset(root,-,sizeof(root));
}
void addedge(int u,int v,int w){
to[cnt]=v;
cost[cnt]=w;
nxt[cnt]=head[u];
head[u]=cnt++;
}
void dfs(int u,int dep){
vis[u]=;
ver[++tot]=u;
first[u]=tot;
R[tot]=dep;
for(int i=head[u];~i;i=nxt[i]) if(!vis[to[i]]){
int v=to[i];
d[v]=d[u]+cost[i];
dfs(v,dep+);
ver[++tot]=u;R[tot]=dep;
}
}
void dfs2(int u,int r){
root[u]=r;
for(int i=head[u];~i;i=nxt[i]) if(root[to[i]]==-)
dfs2(to[i],r);
}
void ST(int n){
for(int i=;i<=n;i++)
dp[i][]=i;
for(int j=;(<<j)<=n;j++){
for(int i=;i+(<<j)-<=n;i++){
int a=dp[i][j-],b=dp[i+(<<(j-))][j-];
dp[i][j]=R[a]<R[b]?a:b;
}
}
}
int RMQ(int l,int r){
int k=;
while((<<(k+))<=r-l+) k++;
int a=dp[l][k],b=dp[r-(<<k)+][k];
return R[a]<R[b]?a:b;
}
int LCA(int u,int v){
int x=first[u],y=first[v];
if(x>y) swap(x,y);
int res=RMQ(x,y);
return ver[res];
}
int Find(int x){
return x==F[x]?x:F[x]=Find(F[x]);
}
void circle(){
for(int i=;i<=n;i++)
F[i]=i;
num=;
memset(cc,-,sizeof(cc));
memset(pos,-,sizeof(pos));
for(int i=;i<=n;i++){
int u=Find(i),v=Find(tow[i]);
if(u==v) cc[i]=++num;
F[u]=v;
}
for(int i=;i<=n;i++) if(cc[i]!=-){
int k=tow[i],tmp=;
pos[i]=++tmp;
root[i]=i;
while(k!=i){
pos[k]=++tmp;
root[k]=k;
cc[k]=cc[i];
k=tow[k];
}
len[cc[i]]=tmp;
}
}
int main(){
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m)){
ini();
for(int i=;i<=n;i++)
scanf("%d",&tow[i]);
circle();
for(int i=;i<=n;i++) if(root[i]!=i){
addedge(tow[i],i,);
addedge(i,tow[i],);
}
for(int i=;i<=n;i++) if(root[i]==i){
dfs2(i,i);
addedge(,i,);
addedge(i,,);
}
dfs(,);
ST(*n-);
int x,y;
while(m--){
scanf("%d%d",&x,&y);
int p=LCA(x,y);
if(p) printf("%d %d\n",d[x]-d[p],d[y]-d[p]);
else{
int rx=root[x],ry=root[y];
if(cc[rx]!=cc[ry]) puts("-1 -1");
else{
int sum=len[cc[rx]];
int d1=d[x],d2=d[y];
if(pos[rx]<pos[ry])
d1+=pos[ry]-pos[rx];
else d1+=(sum-pos[rx]+pos[ry]); int d3=d[x],d4=d[y];
if(pos[ry]<pos[rx]) d4+=pos[rx]-pos[ry];
else d4+=(sum-pos[ry]+pos[rx]); if(max(d1,d2)<max(d3,d4))
printf("%d %d\n",d1,d2);
else if(max(d1,d2)>max(d3,d4))
printf("%d %d\n",d3,d4);
else{
if(min(d1,d2)<min(d3,d4))
printf("%d %d\n",d1,d2);
else if(min(d1,d2)>min(d3,d4))
printf("%d %d\n",d3,d4);
else{
if(d1>=d2) printf("%d %d\n",d1,d2);
else printf("%d %d\n",d3,d4);
}
}
}
}
}
}
return ;
}

hdu 4297的更多相关文章

  1. HDOJ 2111. Saving HDU 贪心 结构体排序

    Saving HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  2. 【HDU 3037】Saving Beans Lucas定理模板

    http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...

  3. hdu 4859 海岸线 Bestcoder Round 1

    http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格 ...

  4. HDU 4569 Special equations(取模)

    Special equations Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u S ...

  5. HDU 4006The kth great number(K大数 +小顶堆)

    The kth great number Time Limit:1000MS     Memory Limit:65768KB     64bit IO Format:%I64d & %I64 ...

  6. HDU 1796How many integers can you find(容斥原理)

    How many integers can you find Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d ...

  7. hdu 4481 Time travel(高斯求期望)(转)

    (转)http://blog.csdn.net/u013081425/article/details/39240021 http://acm.hdu.edu.cn/showproblem.php?pi ...

  8. HDU 3791二叉搜索树解题(解题报告)

    1.题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3791 2.参考解题 http://blog.csdn.net/u013447865/articl ...

  9. hdu 4329

    problem:http://acm.hdu.edu.cn/showproblem.php?pid=4329 题意:模拟  a.     p(r)=   R'/i   rel(r)=(1||0)  R ...

随机推荐

  1. 洛谷——P1613 跑路

    P1613 跑路 题目大意: 小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零.可是小A偏偏又有赖床的坏毛病.于是为了保住自己的工资,小A买了一个十分牛B ...

  2. python中enumerate( )函数的使用

    enumerate( )函数是遍历一个序列中的元素以及元素对应的下标 seq = ['one', 'two', 'three'] for i, element in enumerate(seq): p ...

  3. mysql中的sql查询优化

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在where 及order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行null 值判断,否则将导致引擎放弃使用索引而进 ...

  4. linux -- 视频尺寸-cif、2cif、dcif、D1、HD1、4D1

    1 CIF简介     CIF是常用的标准化图像格式(Common Intermediate Format).在H.323协议簇中,规定了视频采集设备的标准采集分辨率.CIF = 352×288像素 ...

  5. Oracle Auto Increment Column - Sequence as Default Value

        Solution 1: Prior to Oracle 11g, sequence assignment to a number variable could be done through ...

  6. .NET Web API - 去掉讨厌的$id并且强制返回json格式

    // 只返回json字符串,屏蔽自动选择xml格式的可能性,同时去掉讨厌的$id var json = config.Formatters.JsonFormatter; json.Serializer ...

  7. AngularJS:添加检查密码输入是否一致的功能

    感谢作者(http://blog.brunoscopelliti.com/angularjs-directive-to-check-that-passwords-match) 利用AngularJS的 ...

  8. HDU 5392 BC #51

    就是求最大公倍数,但要用分解质因子求. 自己写的WA到爆.... #include<iostream> #include<stdio.h> #include<math.h ...

  9. HDU 4598

    这道题其实不需要考虑具体数值,但可以肯定的是,相连边的两端点必定有一正一负,至于谁正谁负,并不重要,这是可以思考的,很明显的一个二分图性质,如果不满足此条件,是不可能满足题目第二个条件的.所以首先对题 ...

  10. OC基础回想(十二)协议

    在OC基础(十一)中我们讨论了类别和非正式协议的奇异之处.在使用非正式协议时.能够仅仅实现你想要获得响应的方法.也不必在对象中声明不论什么内容来表示该对象可用作托付对象. 全部这些任务能够用最少的代码 ...