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 ...
随机推荐
- js里的深度克隆
ES6 数组克隆 let arr = [1,2,3,4,5]; let arr1 = [...a]; arr1 = ["a","b","c" ...
- [luogu2594 ZJOI2009]染色游戏(博弈论)
传送门 Solution 对于硬币问题,结论是:当前局面的SG值等于所有背面朝上的单个硬币SG值的异或和 对于求单个背面朝上的硬币SG值...打表找规律吧 Code //By Menteur_Hxy ...
- java折半插入排序
代码如下: public class BinaryInsertSort { public static void binaryInsertSort(DataWrap [] data) { System ...
- python - 函数的定义和使用
目录 函数的定义和使用 一. 为什么要用函数? 二. 函数的参数 三. 函数的变量 global和nolocal 四. 递归函数 五. lamabda匿名函数 函数的定义和使用 1 def test( ...
- linux学习4-crontab定时任务
crontab -e 在当前用户下创建定时任务 我们通过这样一张图来了解 crontab 的文档编辑的格式与参数 在了解命令格式之后,我们通过这样的一个例子来完成一个任务的添加,在文档的最后一排加上 ...
- 敏捷开发系列学习总结(2)——Bug修改流程
原则,力求各司其职,简单明了. 1. 测试人员提交bug ⑴ 标题: [ 模块名称 ] 问题描述 ⑵ 内容: 问题重现步骤的描述,最好贴上图片. 因为一图胜万言. ⑶ 指定责任人: 根据bug指定责任 ...
- Android欢迎页面以及引导页面
开发环境:Windows 10 x64,Android Studio 3.0 很多APP都会在启动主界面(MainActivity)之前显示一个短暂的欢迎页面,设置微博,知乎,百度之类APP还是在欢迎 ...
- hdu_1008_Elevator_201308191629
ElevatorTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- 【ACM】hdu_zs3_1006_AB_201308101123
A/B Time Limit : 1000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)Total Submission ...
- N天学习一个linux命令之ps
ps命令 用途 显示系统进程信息 用法 ps [options] 常用选项 选项有三种风格,这里是指Unix风格 (Unix,BSD,GNU LONG OPTIONS) 简单刷选类 -A, -e 显示 ...