hdu 4297
有两个基础需要掌握:
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的更多相关文章
- HDOJ 2111. Saving HDU 贪心 结构体排序
Saving HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 【HDU 3037】Saving Beans Lucas定理模板
http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...
- hdu 4859 海岸线 Bestcoder Round 1
http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格 ...
- HDU 4569 Special equations(取模)
Special equations Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u S ...
- HDU 4006The kth great number(K大数 +小顶堆)
The kth great number Time Limit:1000MS Memory Limit:65768KB 64bit IO Format:%I64d & %I64 ...
- HDU 1796How many integers can you find(容斥原理)
How many integers can you find Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%I64d ...
- hdu 4481 Time travel(高斯求期望)(转)
(转)http://blog.csdn.net/u013081425/article/details/39240021 http://acm.hdu.edu.cn/showproblem.php?pi ...
- HDU 3791二叉搜索树解题(解题报告)
1.题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3791 2.参考解题 http://blog.csdn.net/u013447865/articl ...
- hdu 4329
problem:http://acm.hdu.edu.cn/showproblem.php?pid=4329 题意:模拟 a. p(r)= R'/i rel(r)=(1||0) R ...
随机推荐
- DOM节点的获取
document.getElementById();//id名,在实际开发中较少使用,选择器中多用class id一般只用在顶级层存在 不能太过依赖id document.getElements ...
- div+css 组织结构
<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>家谱 ...
- 求n!(高精度问题)
#include <iostream> #include <stdio.h> #define MAX 10000 using namespace std; void Mul(i ...
- PHP websocket之聊天室实现
PHP部分 <?php error_reporting(E_ALL); set_time_limit(0);// 设置超时时间为无限,防止超时 date_default_timezone_set ...
- Selenium的安装和简单实用——PhantomJS安装
简介 Selenium是一个用于Web应用程序测试的工具. Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE(7, 8, 9, 10, 11),Firefox,S ...
- 对SHH的公钥和私钥的简单理解
SSH是在应用层和传输层基础上的安全协议 SSH提供了两种级别的安全验证: 第一基于密码的安全验证:账号.密码,但可能有别的服务器冒充真正的服务器,无法避免被“中间人”攻击(man-in-the-mi ...
- 神奇的幻方 noip2015day1 T1
题目描述 Description 幻方是一种很神奇的N∗N矩阵:它由数字 1,2,3, … … ,N∗N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个 ...
- nyoj_264_国王的魔镜_201311271800
国王的魔镜 时间限制:3000 ms | 内存限制:65535 KB 难度:1 描述 国王有一个魔镜,可以把任何接触镜面的东西变成原来的两倍——只是,因为是镜子嘛,增加的那部 ...
- x$bh视图
首先,这篇文章是基于如下ORACLE版本. BANNER ------------------------------------------------ Oracle Database 10g En ...
- 学习C#和SQL的书籍
1. <21天学通C#> 周红安等编著 电子工业出版社 2. http://blog.csdn.net/21aspnet/article/details/1682200 3. < ...