题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2125

因为看了TJ又抄了标程,现在感觉还是轻飘飘的……必须再做一遍。

两点间的情况:

1.直到 lca 都没有在一个环上的部分;

2.本来就处在一个环上;

3.本来不在一个环上,快到 lca 的时候开始处在一个环上了。

第一种情况就普通弄就行。处理倍增 lca 数组和根到每个点的最短路dis值。

第二种情况在环上两部分取较短的就行。

第三种情况是前两种的结合。需要找到 p 和 q 刚开始在同一个环上时的那两个进入点 x 和 y。然后dis[ p ] - dis[ x ] + dis[ q ] - dis[ y ]再加上 p、q 环上两部分较短的。

怎么取较短的呢?

可以弄dfs序的距离。

实现的时候第二种和第三种情况可以合并。

细节有一些不明白:环的最高点的深度和环上别的点不一样,也行吗?还有边的数组大小怎么算?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e4+;
int n,m,q,hd[N],xnt=,g[N],len[N],cnt,dep[N],f[N][];
int dis[N],ds[N],fa[N],dfn[N],tim;
bool vis[N];
struct Ed{
int nxt,to,w;bool del;
Ed(int n=,int t=,int w=):nxt(n),to(t),w(w) {del=;}
}ed[N<<];
int tabs(int k){return k<?-k:k;}
void add(int x,int y,int z)
{
ed[++xnt]=Ed(hd[x],y,z);hd[x]=xnt;
}
void spfa()
{
memset(dis,0x3f,sizeof dis);dis[]=;
queue<int> q;q.push();vis[]=;
while(q.size())
{
int k=q.front();q.pop();vis[k]=;//don't forget visk=0!!
for(int i=hd[k],v;i;i=ed[i].nxt)
if(dis[v=ed[i].to]>dis[k]+ed[i].w)
{
dis[v]=dis[k]+ed[i].w;
if(!vis[v])vis[v]=,q.push(v);
}
}
}
void circle(int y,int e)
{
int x=ed[e].to;//!
len[++cnt]=ed[e].w;g[y]=cnt;
ed[e].del=ed[e^].del=;//don't forget del!
add(x,y,);add(y,x,);// edw has no limit--only for bfs the dep
// edw is guaranteed by ds[]
for(e=fa[y];(y=ed[e^].to)!=x;e=fa[y])
{
len[cnt]+=ed[e].w;g[y]=cnt;ed[e].del=ed[e^].del=;
add(x,y,);add(y,x,);
}
len[cnt]+=ed[e].w;g[x]=cnt;
}
void dfs(int cr)
{
dfn[cr]=++tim;
for(int i=hd[cr],v;i;i=ed[i].nxt)
if(!dfn[v=ed[i].to])
{
fa[v]=i;ds[v]=ds[cr]+ed[i].w;dfs(v);
}
else if(i!=(fa[cr]^)&&dfn[v]<dfn[cr])circle(cr,i);//cr!!!
}
void bfs()
{
queue<int> q;q.push();dep[]=;
while(q.size())
{
int k=q.front();q.pop();
for(int i=hd[k],v;i;i=ed[i].nxt)
if(!ed[i].del&&!dep[v=ed[i].to])
{
dep[v]=dep[k]+;q.push(v);
f[v][]=k;
for(int j=;j<=;j++)//j not i
{
f[v][j]=f[f[v][j-]][j-];
}
}
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int p=x,q=y;
for(int i=;i>=;i--)
if(dep[f[x][i]]>=dep[y])x=f[x][i];
if(x==y)return dis[p]-dis[q];
for(int i=;i>=;i--)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
if(g[x]!=g[y]||(!g[x]&&!g[y]))return dis[p]+dis[q]-*dis[f[x][]];//&& !g[x]&&!g[y]!!!
int k=tabs(ds[x]-ds[y]);
return dis[p]-dis[x]+dis[q]-dis[y]+min(k,len[g[x]]-k);
// include p&q in different circle but x&y in the same circle;
//because the dep of nodes in the same circle are almost the same
}
int main()
{
scanf("%d%d%d",&n,&m,&q);int x,y,z;
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
spfa();
dfs();
bfs();
for(int i=;i<=q;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
return ;
}

最新文章

  1. [体感游戏] 1、MPU6050数据采集传输与可视化
  2. c#基础系列(转)
  3. js 多少天以后的时间
  4. 对已经发布订阅的sqlserver进行修改-添加新的表
  5. FME之于规划CAD数据质量检测
  6. 62. 链表重排[Reorder List]
  7. [转]-如何将Eclipse中的项目迁移到Android Studio 中
  8. Linux 虚拟机和物理机配互信出现无法连接
  9. Objective-C 学习笔记(1)
  10. 本地不安装oracle-client,使用pl/sql developer连接数据库
  11. GDKOI2015
  12. BZOJ 1609: [Usaco2008 Feb]Eating Together麻烦的聚餐( LIS )
  13. Android 如何保证service在后台不被kill
  14. Gym 101257G 24 (概率+二分)
  15. Django项目之小博客
  16. SQL查询和删除重复字段的内容
  17. Python_copy_深浅拷贝
  18. NAT 模式下虚拟机安装的centos7 ping主机显示connect: Network is unreachable
  19. item 4: 知道怎么去看推导的类型
  20. js验证整数,浮点数

热门文章

  1. 频繁加载、删除swf造成flash崩溃解决办法
  2. rate limiter - system design
  3. Django 认证系统 cookie &amp; session &amp; auth模块
  4. 3.写一个hello world页面
  5. leetcode第一刷_Permutations
  6. 分布式文件存储——GlusterFS
  7. rewrite_static
  8. python 3 封装
  9. AC自动机的一点理解
  10. ll指令输出解析