有两个基础需要掌握:

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. csrf漏洞利用

    low csrf(cross-site-request forgery),跨站请求伪造. 测试网站 --http://localhost/vulnerability/csrf 修改密码,点击chang ...

  2. CAD调用导角命令,并返回导角的圆弧对象

    主要用到函数说明: _DMxDrawX::SendStringToExecuteFun 把命令当着函数执行,可以传参数,详细说明如下: 参数 说明 IDispatch* pParam 命令参数,IMx ...

  3. asp网站中使用百度ueditor教程.txt

    1.根据网站类型及编码选择相应的ueditor版本,如我的网站编码为gb2312,则选择ueditor 1.43 asp gbk版.2.本机IE浏览器应为8.0或以上,8.0以下的ueditor 1. ...

  4. SDWC 2018 day5

    望得分:100+100+100 实际得分:100+100+100 Problem 1 晨跑(running.cpp/c/pas)[题目描述]为了响应学校的号召,模范好学生王队长决定晨跑.不过由于种种原 ...

  5. 我理解的数据结构(二)—— 栈(Stack)

    我理解的数据结构(二)-- 栈(Stack) 一.栈基础 栈是一种线性结构 相比较数组,栈对应的操作是数组的子集 只能从一端添加元素,也只能从同一端取出元素,这一端称为栈顶 栈是一种后进先出的数据结构 ...

  6. ZooKeeper学习总结(1)——ZooKeeper入门介绍

    1. 概述 Zookeeper是Hadoop的一个子项目,它是分布式系统中的协调系统,可提供的服务主要有:配置服务.名字服务.分布式同步.组服务等. 它有如下的一些特点: 简单 Zookeeper的核 ...

  7. Ajax 请求之_请求类型详解

    $.ajax({ url: "规定发送请求的 URL.默认是当前页面.", type: "post", // 请求类型,默认get // 在回调函数中,无需将j ...

  8. [HDU1403]Longest Common Substring(后缀数组)

    传送门 求两个串的公共子串(注意,这个公共子串是连续的一段) 把两个串连在一起,中间再加上一个原字符串中不存在的字符,避免过度匹配. 求一遍height,再从height中找满足条件的最大值即可. 为 ...

  9. hdu 4046 树状数组

    #include<stdio.h> #include<string.h> #define N  51000 char s[N]; int a[N],n; int number( ...

  10. [bzoj3126][USACO2013]Photo_动态规划_单调队列

    Photo bzoj-3126 题目大意:给你一个n长度的数轴和m个区间,每个区间里有且仅有一个点,问最多能有多少个点. 注释:$1\le n \le 2\cdot 10^5$,$1\le m\le1 ...