Description

为了 随时 与 rainbow快速交流, Freda制造了 两部传呼机 。Freda和 rainbow所在的地方有N座房屋、M条双向 光缆 。每条光缆连接两座房屋, 传呼机发出的信号只能沿着光缆传递,并且 传呼机的信号 从光缆的其中一端传递到另需要花费 t单位时间 。现在 Freda要 进行 Q次试验, 每次选取两座房屋,并想知道 传呼机的信号在这两座房屋之间传递 至少需 要多长时间。 Freda 和 rainbow简直弱爆了有木有T_TT_T ,请你帮他们吧……

N座房屋 通过光缆 一定是连通的, 并且这 M条光缆有以下三类连接情况:

A:光缆不形成环 ,也就是光缆仅 有 N-1条。(30%的数据)

B:光缆只 形成一个环,也就是光缆 仅有 N条。(50%的数据)

C:每条光缆仅在一个环中。(10%数据N,M较小,10%数据N,M较大)

Solution

先看A类数据,显然树上lcalca可以完美解决。

再看一下B类数据,环套树,我们考虑拆掉环。

搜索一遍把环边找出来,特殊处理环边连接的两个点到所求两点的距离即可。

对于C类数据,仙人掌图。

于是我们可以考虑将环拆散,对于每个环,我们找出它们的环顶(这里环顶的定义是进入该环必须经过的点,注意,环顶不属于任何环,因为它可以被多个环包含),然后把环顶向这个环上的点连一条边,边权为该点到环顶的最短路。

具体实现就是开个栈,处理每个环上的点经过环的两条路径的距离即可。

然后原图就变成一棵树了,是不是觉得很简单了!

然而,如果我们直接像A类数据那样的话,会出现一个问题:

我们看,如果(u′,v′)(u',v')在同一个环内,那么它们的最短距离就可能不需要经过lcalca,那么统计的时候答案就可能大了。

这时,我们先前统计的环上的两条路径就派上用场了。

记两条路径分别为l1l1,l2l2,那么这两个点的最短路就是:
min(l1x+l2y,l2x+l1y,|l1x−l1y|)min(l1_x+l2_y,l2_x+l1_y,|l1_x-l1_y|)(|a||a|表示aa的绝对值)

所以,我们求lcalca时只需走到lcalca的儿子即可。

注意细节。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 20010
#define M 40010
using namespace std;
int to[M],next[M],last[M],val[M],num=0;
int nt[M],nn[M],nl[M],nv[M],cnt=0;
int dfn[N];
int top=0;
int f[N][15],g[N][15];
int fa[N];
int c1[N],c2[N];
int bl[N],zx[N];
int zz=0;
int d[N];
struct stack{int x,s;
}st[N];
int tt=0;
int abs(int x)
{return x<0?-x:x;
}
void link(int x,int y,int c)
{num++;to[num]=y;next[num]=last[x];last[x]=num;val[num]=c;
}
void nlink(int x,int y,int c)
{cnt++;nt[cnt]=y;nn[cnt]=nl[x];nl[x]=cnt;nv[cnt]=c;
}
void dfs(int x)
{dfn[x]=++tt;for(int i=last[x];i;i=next[i]){int v=to[i];if(v!=fa[x] && !dfn[v]){fa[v]=x;top++;st[top].x=v;st[top].s=val[i];dfs(v);}else if(v!=fa[x] && dfn[v]<dfn[x]){zz++;int p=top,tmp=val[i];while(st[p].x!=v && p){c1[st[p].x]=tmp;tmp+=st[p].s;p--;}tmp=st[p+1].s;fo(i,p+1,top){zx[st[i].x]=v;bl[st[i].x]=zz;c2[st[i].x]=tmp;int jx=min(c1[st[i].x],c2[st[i].x]);nlink(st[i].x,v,jx);nlink(v,st[i].x,jx);tmp+=st[i+1].s;}}}top--;
}
bool vis[N];
void cxlb(int x)
{vis[x]=true;for(int i=last[x];i;i=next[i]){int v=to[i];if(v!=fa[x] && !vis[v]){if((bl[x]!=bl[v] || !bl[x] && !bl[v]) && zx[v]!=x && zx[x]!=v){nlink(x,v,val[i]);nlink(v,x,val[i]);}cxlb(v);}}
}
int sbll=0;
void find(int x)
{for(int i=nl[x];i;i=nn[i]){int v=nt[i];if(v!=f[x][0]){f[v][0]=x;g[v][0]=nv[i];d[v]=d[x]+1;find(v);}}
}
int lca(int x,int y)
{int tmp=0;if(d[x]>d[y]) swap(x,y);fd(i,14,0)while(d[f[y][i]]>=d[x])tmp+=g[y][i],y=f[y][i];if(x==y) return tmp;fd(i,14,0)while(f[x][i]!=f[y][i]) {tmp+=g[x][i]+g[y][i];x=f[x][i];y=f[y][i];}if(x!=y && bl[x] && bl[x]==bl[y]) tmp+=min(min(c1[x]+c2[y],c1[y]+c2[x]),min(abs(c2[x]-c2[y]),abs(c1[x]-c1[y])));else tmp+=g[x][0]+g[y][0];return tmp;
}
int main()
{int n,m,q;cin>>n>>m>>q;fo(i,1,m){int x,y,t;scanf("%d %d %d",&x,&y,&t);link(x,y,t);link(y,x,t);}dfs(1);cxlb(1);find(1);d[0]=-1;fo(j,1,14)fo(i,1,n){f[i][j]=f[f[i][j-1]][j-1];g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1];}fo(i,1,q){int x,y;scanf("%d %d",&x,&y);printf("%d\n",lca(x,y));}
}

【BZOJ30472125】Freda的传呼机相关推荐

  1. 【NOIP2013模拟】Freda的传呼机

    [NOIP2013模拟]Freda的传呼机 Time Limits: 100 ms Memory Limits: 131072 KB Description 为了 随时 与 rainbow快速交流, ...

  2. Acwing 360. Freda的传呼机(仙人掌图重构,lca)

    为了随时与rainbow快速交流,Freda制造了两部传呼机.Freda和rainbow所在的地方有N座房屋.M 条双向光缆. 每条光缆连接两座房屋,传呼机发出的信号只能沿着光缆传递,并且传呼机的信号 ...

  3. 「Nescafé26」 Freda的传呼机 【树上倍增+图论】

    题目: 为了随时与rainbow快速交流,Freda制造了两部传呼机.Freda和rainbow所在的地方有N座房屋.M条双向光缆.每条光缆连接两座房屋,传呼机发出的信号只能沿着光缆传递,并且传呼机的 ...

  4. jzoj3395 Freda的传呼机

    Description 为了 随时 与 rainbow快速交流, Freda制造了 两部传呼机 .Freda和 rainbow所在的地方有N座房屋.M条双向 光缆 .每条光缆连接两座房屋, 传呼机发出 ...

  5. 「Nescafé26」 Freda的传呼机 【最短路径+树上倍增】

    题目: 为了随时与rainbow快速交流,Freda制造了两部传呼机.Freda和rainbow所在的地方有N座房屋.M条双向光缆.每条光缆连接两座房屋,传呼机发出的信号只能沿着光缆传递,并且传呼机的 ...

  6. 【NOIP2013模拟】Freda的传呼机 题解+代码

    这题又有点像码农题!! Description 为了 随时 与 rainbow快速交流, Freda制造了 两部传呼机 .Freda和 rainbow所在的地方有N座房屋.M条双向 光缆 .每条光缆连 ...

  7. bzoj3047: Freda的传呼机 2125: 最短路

    Description 为了随时与rainbow快速交流,Freda制造了两部传呼机.Freda和rainbow所在的地方有N座房屋.M条双向光缆.每条光缆连接两座房屋,传呼机发出的信号只能沿着光缆传 ...

  8. JZOJ3395. 【NOIP2013模拟】Freda的传呼机

    题目大意 给一个包含N个节点和M条双向边的图(保证每条边只会最多出现在一个环中,即仙人掌)和Q个询问. 输入x,y,t表示x,y之间有一条长度为t的双向边. 接下来Q个询问,每个询问(u,v)求(u, ...

  9. bzoj3047: Freda的传呼机bzoj2125: 最短路

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3047 http://www.lydsy.com/JudgeOnline/problem.ph ...

最新文章

  1. grpc 传递上下文_grpc 源码笔记 02:ClientConn
  2. 3种时间序列混合建模方法的效果对比和代码实现
  3. system.DateTime ToDateTime(System.String)”,因此该方法无法转换为存储表达式-解决方法...
  4. NgModule中的声明,提供程序和导入有什么区别?
  5. 《他其实没那么喜欢你》经典台词(2)
  6. BZOJ-1934-Vote善意的投票-SHOI2007
  7. OS / Linux / clone、fork、vfork 与 pthread_create 创建线程有何不同
  8. rowid 对应mysql_请教一下相当于MySQL中Oracle的RowID
  9. error_reporting()的用法
  10. VS Code前端开发利器-常用快捷键
  11. 在WinForm中使用Web Service来实现软件自动升级
  12. MongoDB聚合(aggregate)常用操作及示例
  13. 计算软件介绍siesta、vasp、wien2k、PWSCF、Materials Studio
  14. ArcGIS计算地形湿度指数
  15. android apk旋转,系统的屏幕旋转弱爆了!超强屏幕旋转控制APP
  16. Surface pro3电源管理
  17. 网络计算机amd,AMD多屏显示设置指南_计算机硬件和网络_IT /计算机_信息
  18. threw ‘java.lang.NullPointerException‘ exception // toString()
  19. 计算器四则运算c语言,C语言:基于命令行的四则运算计算器
  20. HTML语义化标签理解

热门文章

  1. html如何制作电子邮件地址怎么写,如何制作html电子邮件?
  2. 商家如何入驻微信小程序
  3. maxwell deamon 监听mysql binlog 二进制文件实现数据同步到
  4. 计算机应用基础实验报告心得体会,计算机应用基础实训总结报告
  5. Java发送手机短信
  6. C# 中使用面向切面编程(AOP)中实践代码整洁(转)
  7. java毕业设计坝上长尾鸡养殖管理系统Mybatis+系统+数据库+调试部署
  8. JAVA 获取某天、某周、某月、某年的开始时间和结束时间
  9. 清华计算机校友郭毅可院士履新,任港科大首席副校长
  10. 全网最新-扶风视频解析计费系统,2022优化免授权版(赠接口轮询插件)