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 ...
随机推荐
- inline-block兼容IE7
{ display:inline-block; *display:inblock; *zoom:1 }
- Navicat premium连接Oracle报ORA-12514错误
1:ORA-12514 原因:Service Name/SID中的值填的有问题,默认的是ORCL,这个值如果在安装Oracle的时候填的不是ORCL,那就会出现这个错误 解决方法:找到Oracle安装 ...
- XOR Queries
XOR Queries 时间限制: 1000ms 内存限制: 256M 描述 给出一个长度为n的数组C,回答m个形式为(L,R,A,B)的询问,含义为存在多少个不同的数组下标k∈[L,R]满足C[ ...
- Ubuntu 安装有道词典
本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51302546 官网首页:有道词典 其中 ...
- Sencha Touch中 xclass和xtype区别
1.xclass 就是 Ext.create(xclass) 和 xtype一样的性质,不一定非要是自己创建的. 2.xtype是xclass的简称. 3.使用xtype前,你要new的对象,先要re ...
- [bzoj3676]回文串[后缀数组+Manacher]
后缀数组+Manacher #include <iostream> #include <cstdio> #include <cstdlib> #include &l ...
- [bzoj3669][Noi2014]魔法森林_LCT_并查集
魔法森林 bzoj-3669 Noi-2014 题目大意:说不明白题意系列++……题目链接 注释:略. 想法:如果只有1个参量的话spfa.dij什么的都上来了. 两个参量的话我们考虑,想将所有的边按 ...
- HTML5:控件自动获得焦点
在HTML5中,页面打开后,需要指定的控件自动获得焦点很简单,只需要一个属性就可以实现 - autofocus. 示例如下: <input type="text" auto ...
- JAVA正則表達式小总结
近期项目中正在做后台校验,而后台校验也基本都是使用正則表達式校验.本文做一些粗略的总结. 1.字符串长度:.{1,10},注意有一个点在{}前,表示匹配全部.'{}'之前一定是一个捕获组,因此假设有其 ...
- 【Android开发VR实战】三.开发一个寻宝类VR游戏TreasureHunt
转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53939303 本文出自[DylanAndroid的博客] [Android开发 ...