原文链接https://www.cnblogs.com/zhouzhendong/p/NOI2018Day1T1.html

题目传送门 - 洛谷P4768

题意

  给定一个无向连通图,有 $n$ 个点 $m$ 条边,每条边有两个属性:海拔$(a)$、距离$(l)$。

  有 $Q$ 组询问,每组询问两个数 $v,p$,表示询问从点 $v$ 出发,从第一次走海拔高度不超过 $p$ 的边起算,问行走距离最小为多少。(即,在第一次走海拔高度不超过 $p$ 的边之前,走的所有边都是免费的)

  $T$ 组数据,强制在线。

  $1\leq T\leq 3,\ \ \ n\leq 2\times 10^5,\ \ \ m\leq 4\times 10^5,\ \ \ \ Q\leq 4\times 10^5,\ \ \ a,p\leq 10^9,\ \ \ l\leq 10^4,\ \ \ 1\leq v\leq n$

题解

  洛谷老爷机貌似非常慢,比€€F老爷机慢。

  我们先把问题转化一下。

  预处理出点 $1$ 到每一个点的最短路长度 $dis$。

    这个东西还好我用了堆优化的 Dijkstra 。后来听说: 关于 SPFA                                           它死了

  每一次询问,就是:连接海拔高度大于 $p$ 的所有边,求 $v$ 能到达的点中的最小 $dis$ 值。

  首先考虑离线做法。

  我们按照海拔从高到低依次加边,用 kruskal 的做法生成森林。维护一下连通块的最小 $dis$ 值,然后顺便询问就可以了。

  但是强制在线。

  1.  可持久化并查集 $\Longrightarrow$ 可能会被卡常数。

  2.  Kruskal 重构树 + 倍增。

  我们令合并时的新节点权值为当前海拔,然后预处理祖先倍增表。

  每次询问,倍增到深度最小的海拔大于 $p$ 的节点,输出子树最小 $dis$ 值即可。

  作为同步赛选手写出来了,但是本机测大样例最后一个点 $1.26s$ 。放到 UOJ 上面自定义测试一下 , $0.183s$ ……

  事实证明€€F老爷机跑的还是挺快的,期望得分:100,实际得分:100。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
int read(){
char ch=getchar();
int x=0;
while (!('0'<=ch&&ch<='9'))
ch=getchar();
while ('0'<=ch&&ch<='9')
x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x;
}
const int N=200005,M=400005;
int T,n,m;
struct Gragh{
int cnt,y[M*2],z[M*2],nxt[M*2],fst[N];
void clear(){
cnt=0;
memset(fst,0,sizeof fst);
}
void add(int a,int b,int c){
y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g;
struct Edge{
int x,y,h;
Edge(){}
Edge(int _x,int _y,int _h){
x=_x,y=_y,h=_h;
}
friend bool operator < (Edge a,Edge b){
return a.h>b.h;
}
}e[M];
int dis[N],vis[N];
struct Node{
int x,d;
Node(){}
Node(int _x,int _d){
x=_x,d=_d;
}
friend bool operator < (Node x,Node y){
return x.d>y.d;
}
};
priority_queue <Node> Q;
void Dijkstra(){
while (!Q.empty())
Q.pop();
for (int i=1;i<=n;i++)
dis[i]=2e9+5;
dis[1]=0;
memset(vis,0,sizeof vis);
Q.push(Node(1,0));
while (!Q.empty()){
Node now=Q.top();
Q.pop();
int x=now.x;
if (vis[x])
continue;
vis[x]=1,dis[x]=now.d;
for (int i=g.fst[x];i;i=g.nxt[i])
Q.push(Node(g.y[i],dis[x]+g.z[i]));
}
}
const int N2=N*2;
int fa[N2],son[N2][2],h[N2],mindis[N2],Fa[N2][20];
int getf(int x){
return fa[x]==x?x:fa[x]=getf(fa[x]);
}
int Qu[N2],head,tail;
int main(){
// freopen("return.in","r",stdin);
// freopen("return.out","w",stdout);
T=read();
while (T--){
n=read(),m=read();
g.clear();
for (int i=1;i<=m;i++){
int x=read(),y=read(),l=read(),a=read();
g.add(x,y,l);
g.add(y,x,l);
e[i]=Edge(x,y,a);
}
Dijkstra();
sort(e+1,e+m+1);
memset(fa,0,sizeof fa);
for (int i=1;i<=n*2;i++)
fa[i]=i;
for (int i=1;i<=n;i++)
h[i]=e[1].h+1;
int cnt=n;
memset(son,0,sizeof son);
memset(h,0,sizeof h);
for (int i=1;i<=m;i++){
int x=getf(e[i].x),y=getf(e[i].y);
if (x==y)
continue;
h[++cnt]=e[i].h;
son[cnt][0]=x,son[cnt][1]=y;
fa[x]=fa[y]=cnt;
}
head=tail=0;
Qu[++tail]=cnt;
while (head<tail){
int x=Qu[++head];
for (int i=1;i<19;i++)
Fa[x][i]=Fa[Fa[x][i-1]][i-1];
for (int i=0;i<2;i++){
int y=son[x][i];
if (y){
Fa[y][0]=x;
Qu[++tail]=y;
}
}
}
for (int i=tail;i>0;i--){
int x=Qu[i];
if (x<=n)
mindis[x]=dis[x];
else
mindis[x]=min(mindis[son[x][0]],mindis[son[x][1]]);
}
int q=read(),K=read(),S=read();
int lastans=0;
h[0]=-1;
while (q--){
int v=read(),p=read();
v=(v+K*lastans-1)%n+1;
p=(p+K*lastans)%(S+1);
for (int i=18;i>=0;i--)
if (h[Fa[v][i]]>p)
v=Fa[v][i];
printf("%d\n",lastans=mindis[v]);
}
}
// fclose(stdin);
// fclose(stdout);
return 0;
}

  

NOI2018Day1T1 归程 并查集 kruskal kruskal重构树 倍增表 Dijkstra的更多相关文章

  1. BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra

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

  2. BZOJ_5415_[Noi2018]归程_kruscal重构树+倍增+最短路

    BZOJ_5415_[Noi2018]归程_kruscal重构树+倍增 Description www.lydsy.com/JudgeOnline/upload/noi2018day1.pdf 好久不 ...

  3. LOJ #2718. 「NOI2018」归程(Dijkstra + Kruskal重构树 + 倍增)

    题意 给你一个无向图,其中每条边有两个值 \(l, a\) 代表一条边的长度和海拔. 其中有 \(q\) 次询问(强制在线),每次询问给你两个参数 \(v, p\) ,表示在 \(v\) 出发,能开车 ...

  4. hdu 3938 Portal(并查集+离线+kruskal)2011 Multi-University Training Contest 10

    搜了题解才把题搞明白.明白之后发现其实题意很清晰,解题思路也很清晰,只是题目表述的很不清晰…… 大意如下—— 给你一个无向图,图中任意两点的距离是两点间所有路径上的某一条边,这条边需要满足两个条件:1 ...

  5. 并查集板子+kruskal

    最近在学最小生成树得时候又用到了并查集,一起来整理一下 1.并查集 并查集就是字面意思,将两个单独得集合合并成一个大的集合. 并查集关键在于两个操作:合并和查找 先要完成查找操作(合并操作在查找的基础 ...

  6. LOJ.2718.[NOI2018]归程(Kruskal重构树 倍增)

    LOJ2718 BZOJ5415 洛谷P4768 Rank3+Rank1无压力 BZOJ最初还不是一道权限题... Update 2019.1.5 UOJ上被hack了....好像是纯一条链的数据过不 ...

  7. 最小生成数(并查集)Kruskal算法

    并查集:使用并查集可以把每个连通分量看作一个集合,该集合包含连通分量的所有点.这两两连通而具体的连通方式无关紧要,就好比集合中的元素没有先后顺序之分,只有属于和不属于的区别.#define N 100 ...

  8. 【BZOJ 3732】 Network Kruskal重构树+倍增LCA

    Kruskal重构树裸题, Sunshine互测的A题就是Kruskal重构树,我通过互测了解到了这个神奇的东西... 理解起来应该没什么难度吧,但是我的Peaks连WA,,, 省选估计要滚粗了TwT ...

  9. BZOJ3732Network——kruskal重构树+倍增+LCA/最小生成树+倍增

    题目描述 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 & ...

随机推荐

  1. [HTTP]Etag的工作流程

    1. 浏览器首次访问该资源时,web服务器返回资源的同时,响应报文头携带ETag标签: 2. 浏览器将保存该Etag标签的值: 3. 当浏览器发起下一次请求,请求报文头将会携带 If-None-Mat ...

  2. redhat7.3安装python3 pip3

    首先系统自带的python是python2 我们需要安装一个python3(这里的所有源码包都可以在环境中准备好,这样没有网也可以进行安装) 安装python 1.安装环境 # yum -y inst ...

  3. Oracle 之 外部表

    一.外部表概述 外部表只能在Oracle 9i 之后来使用.简单地说,外部表,是指不存在于数据库中的表. 通过向Oracle 提供描述外部表的元数据,我们可以把一个操作系统文件当成一个只读的数 据库表 ...

  4. PHP7运行环境搭建(Windows7)

    注:本文来源于<    PHP7运行环境搭建(Windows7)   > php7号称能直追facebook的HHVM,为了体验一把传说中的高性能,我特意在本地电脑上尝试着安装了php7, ...

  5. Confluence 6 启用主题评论

    页面或者博客页面中显示的评论以下面 2 种方式显示: 主题模式(Threaded):以继承回复的方式显示页面的评论.每一回复的评论将会在不同评论之间显示,以表示各个评论之间的关系. 平面模式(Flat ...

  6. Linux超级守护进程——xinetd

    一 Linux守护进程 Linux 服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户.提供这些服务的程序是由运行在后台的守护进程来执行的. ...

  7. 字符串为空的比较 ==与equals() 区别(キ`゚Д゚´)!!基础很重要 !!!

    情况描述:我提交的代码,让老大审批了一次,讲真的,对于我来说受益匪浅,其中有一个印象很深的内容:一个字符串是否为空的判断,我以前敲代码一直都是这样写的,可是从来都没有意识到这个东西. 代码: if(s ...

  8. medir设置

    setting中 MEDIA_URL="/media/"MEDIA_ROOT=os.path.join(BASE_DIR, "app01","medi ...

  9. python之路第二天

    为何要有操作系统 为了让程序员更轻松的完成命令电脑工作而存在的,控制硬件,服务于软件. 操作系统的位置 操作系统位于软件和硬件之间.操作系统由内核(运行于内核态,控制硬件)和系统调用(运行于用户态,为 ...

  10. jenkins原理

      原理:Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. 直白的说:这个jenkins是CI ...