题目链接

题目大意:给定一张$n$个点$m$条边的无向图。每条边有长度和海拔。有$Q$次询问,每次给定起点$v$和当天水位线$p$,每次终点都是$1$。人可以选择坐车或走路,车只能在海拔大于水位线的路上跑。问人步行的最小距离。

----------------------------------

我们可以转化一下题意:在$v$到$1$的路径上寻找断点$u$,使得从$v$到$u$的路径上车都可以跑,且从$u$到$1$步行的路径是满足前置条件的最短的一条路。

显然从$v$开车出发可以到达的点路径的海拔都是大于水位线的。

于是我们可以用$kruskal$重构树求解。(虽然我也不知道为什么用重构树,但是学姐讲课就是这么讲的

我们将边以海拔作为关键字降序排序,构建一颗形如小根堆的$kruskal$重构树。对于每次询问我们找出树上深度最浅且海拔大于$p$的结点,由$kruskal$重构树的性质可知,它子树的所有结点都可由$v$开车到达。求解这个结点可以倍增解决,两行搞定。

对于最短路,因为是无向边,我们可以预处理$1$的单源最短路径。然后对重构树进行$dfs$便可求出子树内的最短路。

PS:关于$spfa$,它死了。

时间复杂度$O(T(q\log n+n))$

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=;
int n,m,Q,T,K,S,val[maxn],tot,minn[maxn],f[maxn],fa[maxn][],last;
int head[maxn],cnt,dis[maxn],vis[maxn];
struct edge{int next,to,dis;}edge[maxn];
struct Node{int x,y,z;}a[maxn];
struct node
{
int dis,pos;
bool operator < (const node &x) const
{
return x.dis<dis;
}
};
priority_queue<node> q;
bool cmp(Node x,Node y){return x.z>y.z;}
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if (ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void add(int from,int to,int dis)
{
edge[++cnt].next=head[from];
edge[cnt].to=to;
edge[cnt].dis=dis;
head[from]=cnt;
}
inline void dijkstra()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,,sizeof(vis));
dis[]=;q.push((node){dis[],});
while(!q.empty())
{
int now=q.top().pos;q.pop();
if (vis[now]) continue;
vis[now]=;
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
if (dis[to]>dis[now]+edge[i].dis)
{
dis[to]=dis[now]+edge[i].dis;
if (!vis[to]) q.push((node){dis[to],to});
}
}
}
}
inline int find(int x)
{
if(x==f[x]) return x;
return f[x]=find(f[x]);
}
inline void dfs(int now)
{
minn[now]=dis[now];
for (int i=head[now];i;i=edge[i].next)
{
int to=edge[i].to;
fa[to][]=now;
dfs(to);
minn[now]=min(minn[now],minn[to]);
}
}
inline void kruskal()
{
memset(head,,sizeof(head));cnt=;
sort(a+,a+m+,cmp);
for (int i=;i<=n;i++) f[i]=i;
for (int i=;i<=m;i++)
{
int xx=find(a[i].x),yy=find(a[i].y);
if (xx==yy) continue;
val[++tot]=a[i].z;
f[xx]=f[yy]=f[tot]=tot;
add(tot,xx,);add(tot,yy,);
}
dfs(tot);
}
inline void clear()
{
memset(head,,sizeof(head));cnt=;
memset(fa,,sizeof(fa));
memset(minn,0x3f,sizeof(minn));
}
signed main()
{
T=read();
while(T--)
{
clear();
n=read(),m=read();tot=n;last=;
for (int i=;i<=m;i++)
{
int u=read(),v=read(),d=read(),h=read();
add(u,v,d);add(v,u,d);
a[i].x=u,a[i].y=v,a[i].z=h;
}
dijkstra();
kruskal();
for (int j=;(<<j)<=tot;j++)
for (int i=;i<=tot;i++)
fa[i][j]=fa[fa[i][j-]][j-];
Q=read(),K=read(),S=read();
while(Q--)
{
int v=read(),p=read();
v=(v+K*last-)%n+;
p=(p+K*last)%(S+);
for (int j=;j>=;--j)
if(fa[v][j]&&val[fa[v][j]]>p) v=fa[v][j];
printf("%lld\n",last=minn[v]);
}
}
return ;
}

【NOI2018】归程 题解(kruskal重构树+最短路)的更多相关文章

  1. [luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树)

    [luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树) 题面 题面较长,这里就不贴了 分析 看到不能经过有积水的边,即不能经过边权小于一定值的边,我们想到了kru ...

  2. Luogu P4768 [NOI2018]归程(Dijkstra+Kruskal重构树)

    P4768 [NOI2018]归程 题面 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 \(n\) 个节点. \(m\) 条边的无向连通图(节点的编 ...

  3. P4768 [NOI2018]归程(kruskal 重构树)

    洛谷P4768 [NOI2018]归程 LOJ#2718.「NOI2018」归程 用到 kruskal 重构树,所以先说这是个啥 显然,这和 kruskal 算法有关系 (废话 这个重构树是一个有点权 ...

  4. NOI2018归程(Kruskal重构树)

    题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n). 我们依次用 l,a 描述一条边的长度. ...

  5. 「NOI 2018」归程「Kruskal 重构树」

    题解 Kruskal重构树:每次一条边连接两个集合,建一个新点,点权为该边边权:把这两个集合的根连向新点. 性质:(如果求的是最大生成树)叶子结点是图中实际结点:叶子到根路径上点权递减:两点间lca的 ...

  6. loj2718 「NOI2018」归程[Kruskal重构树+最短路]

    关于Kruskal重构树可以翻阅本人的最小生成树笔记. 这题明显裸的Kruskal重构树. 然后这题限制$\le p$的边不能走,实际上就是要满足走最小边权最大的瓶颈路,于是跑最大生成树,构建Krus ...

  7. NOI2018 D1T1 洛谷P4768 归程 (Kruskal重构树)

    实际上是一个最短路问题,但加上了海拔这个条件限制,要在海拔<水位线p中找最短路. 这里使用Kruskal重构树,将其按海拔建成小根堆,我们就可以在树中用倍增找出他不得不下车的点:树中节点有两个权 ...

  8. 【BZOJ5415&UOJ393】归程(Kruskal重构树,最短路)

    题意:From https://www.cnblogs.com/Memory-of-winter/p/11628351.html 思路:先从1开始跑一遍dijkstra,建出kruskal重构树之后每 ...

  9. 【NOI 2018】归程(Kruskal重构树)

    题面在这里就不放了. 同步赛在做这个题的时候,心里有点纠结,很容易想到离线的做法,将边和询问一起按水位线排序,模拟水位下降,维护当前的各个联通块中距离$1$最近的距离,每次遇到询问时输出所在联通块的信 ...

随机推荐

  1. 在Linux下安装zotero

    背景 系统:deepin15 zotero5.0 本来deepin的商店里是有zotero的,但貌似商店里的太老了,安装完打开之后什么功能都不能用,点击按钮没有反应.无奈之下,只能手动安装了 网上的教 ...

  2. 核心知识点:python入门

    目录 一.python入门day1-day24 day01-03 编程语言 day04 变量 day05 垃圾回收机制(GC机制) 1 引用计数 2 标记清除 3 分代回收 day05 程序交互与基本 ...

  3. 利用docker部署oxidized网络设备备份系统

    随着网络设备的增多,通过人手备份网络设备倍感压力,而且效率低.有编程基础的人可能会通过Python的parimiko 或者netmiko 连接到设备操作 把文件通过ftp 上传到FTP服务器, 在通过 ...

  4. mui点击蒙版点击蒙版让其不自动关闭

    var mask = mui.createMask(callback);//callback为用户点击蒙版时自动执行的回调: mask.show();//显示遮罩 mask.close();//关闭遮 ...

  5. HTB::OpenAdmin

    实验环境 渗透过程 0x01 信息搜集 sudo nmap -sS -p1-10000 -sV -sC -T4 10.10.10.171 开放了22(SSH)端口和80(HTTP)端口 访问80端口, ...

  6. 批量删除当前文件夹下面的.svn文件夹

    for /r . %%a in (.) do @if exist "%%a\.svn" rd /s /q "%%a\.svn 使用方法: 新建text文档,复制上面的文本 ...

  7. 数据可视化之DAX篇(二)Power BI中的度量值和计算列,你搞清楚了吗?

    https://zhuanlan.zhihu.com/p/75462046 对于初学者,总是会把度量值和计算列搞混,我也经常碰到这样的问题,有些星友用文章中的代码总是报错,发给我一看,才知道TA把本来 ...

  8. 数据可视化之PowerQuery篇(四)二维表转一维表,看这篇文章就够了

    https://zhuanlan.zhihu.com/p/69187094 数据分析的源数据应该是规范的,而规范的其中一个标准就是数据源应该是一维表,它会让之后的数据分析工作变得简单高效. 在之前的文 ...

  9. Python: 如何判断远程服务器上Excel文件是否被人打开

    最近工作中需要去判断远程服务器上的某个Excel文件是否被打开,如果被人打开,则等待,如果没人打开使用,则去填写数据进Excel文件. 开始想的很简单,和其他语言一样,比如C#,打开文件,如果报错说明 ...

  10. Tips1:考虑用静态工厂方法代替构造器

    用静态工厂方法来代替构造器为外界提供对象 描述: 静态工厂方法代替构造器来给外界提供对象,创建对象依然是由构造器来完成的 创建对象和提供对象: 创建对象的方式: 构造器 提供对象来哦方式: 构造器 类 ...