题解 NOI2018 归程

题意

本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定。 魔力之都可以抽象成一个 n 个节点、m 条边的无向连通图(节点的编号从 1 至 n)。我们依次用 l,a 描述一条边的长度、海拔。 作为季风气候的代表城市,魔力之都时常有雨水相伴,因此道路积水总是不可避免 的。由于整个城市的排水系统连通,因此有积水的边一定是海拔相对最低的一些边。我们用水位线来描述降雨的程度,它的意义是:所有海拔不超过水位线的边都是有积水的。

Yazid 是一名来自魔力之都的OIer,刚参加完ION2018 的他将踏上归程,回到他 温暖的家。 Yazid 的家恰好在魔力之都的 1 号节点。对于接下来 Q 天,每一天Yazid 都会告诉你他的出发点 v ,以及当天的水位线p。 每一天,Yazid 在出发点都拥有一辆车。这辆车由于一些故障不能经过有积水的边。 Yazid 可以在任意节点下车,这样接下来他就可以步行经过有积水的边。但车会被留在他下车的节点并不会再被使用。 需要特殊说明的是,第二天车会被重置,这意味着:

车会在新的出发点被准备好。
Yazid 不能利用之前在某处停放的车。 Yazid 非常讨厌在雨天步行,因此他希望在完成回家这一目标的同时,最小化他步行经过的边的总长度。请你帮助 Yazid 进行计算。 本题的部分测试点将强制在线,具体细节请见【输入格式】和【子任务】。

解法

作为NOI的第一道题,此题的价值不必多说,但是卡spfa这一点真的是引起人神共愤

现在我们要考虑如何做这道题。

因为高度低的边容易积水,有了等于没有,所以我们可以先求出一个最大生成树,将问题转移到树上。

这时,相当于我们要找到这棵树上对应边权的最值。

那么就会想到kruskal重构树。

重构树有三个性质:

1.树上除叶子结点以外的点都对应着原来生成树中的边,叶子结点就是原来生成树上的节点。

2.由于新点的创建顺序与原来生成树上边权的大小有关,可以发现,从每个点到根节点上除叶子结点外按顺序访问到的点的点权是单调的。

3.出于kruskal算法贪心的性质,两个点u和v的lca的点权就对应着它们最小生成树上的瓶颈。

那么我们考虑对于一个点权大于水位线的虚拟节点u,在他的子树内的所有叶子节点两两路径上的瓶颈必然大于水位线,也就是说任意两个叶子节点可以免费的到达。那么这个节点子树内的叶子节点的走路里程就是这些叶子中到1的最小距离。

这样我们每天从v向上跳,找到深度最小的点权大于水位线的虚拟节点就可以了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#include <vector>
#include <queue>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
x=0;T k=1;char c=getchar();
while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
}
const int maxn=200000+15;
const int maxm=400000+15;
struct node {
int u,v,h;
bool operator < (const node& a) const {
return h>a.h;
}
node (int u=0,int v=0,int h=0):u(u),v(v),h(h){}
}bian[maxm]; int fa[maxn*2],anc_w[2*maxn];
int _find(int x) {
return x==fa[x]?x:fa[x]=_find(fa[x]);
} vector<int> G_tree[maxn*2];
void add_edge_tree(int u,int v) {
G_tree[u].push_back(v);
G_tree[v].push_back(u);
} struct Edge {
int u,v,w;
Edge(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
};
vector<int> G[maxn];
vector<Edge> edge;
void add_edge(int u,int v,int w) {
edge.push_back(Edge(u,v,w));
edge.push_back(Edge(v,u,w));
int ecnt=edge.size();
G[u].push_back(ecnt-2);
G[v].push_back(ecnt-1);
} struct Node{
int id,d;
Node(int id=0,int d=0):id(id),d(d){}
bool operator < (const Node a) const{
return d>a.d;
}
};
priority_queue<Node> q;
int n,m,cnt;
int d[maxn];
bool vis[maxn];
void dij() {
for(int i=2;i<=n;i++) d[i]=INF;del(vis,0);
q.push(Node(1,0));
while(!q.empty()) {
Node u=q.top();q.pop();
if(vis[u.id]) continue;
vis[u.id]=1;
for(int i=0;i<G[u.id].size();i++) {
Edge& e=edge[G[u.id][i]];
if(d[e.v]>d[u.id]+e.w) {
d[e.v]=d[u.id]+e.w;
q.push(Node(e.v,d[e.v]));
}
}
}
} int anc[maxn*2][25],minn[2*maxn];
void dfs(int u,int f) {
minn[u]=INF;anc[u][0]=f;
if(u<=n) minn[u]=d[u];
for(int i=0;i<G_tree[u].size();i++) {
int v=G_tree[u][i];
if(v==f) continue;
dfs(v,u);
minn[u]=min(minn[u],minn[v]);
}
} void _init() {
for(int i=1;i<=n;i++) G[i].clear();
for(int i=1;i<=cnt;i++) G_tree[i].clear();
edge.clear();
} int main()
{
int id;read(id);
while(id--) {
read(n),read(m);
for(int i=1;i<=n;i++) fa[i]=i;
int u,v,h,w;
for(int i=1;i<=m;i++) {
read(u),read(v),read(w),read(h);
bian[i]=node(u,v,h);
add_edge(u,v,w);
}
dij();
sort(bian+1,bian+1+m);
int k=0;cnt=n;
for(int i=1;i<=m;i++) {
int f1=_find(bian[i].u),f2=_find(bian[i].v);
if(f1==f2) continue;
anc_w[++cnt]=bian[i].h;
fa[cnt]=fa[f2]=fa[f1]=cnt;//要更新
add_edge_tree(f1,cnt);add_edge_tree(f2,cnt);
++k;
if(k==n-1) break;
}
dfs(cnt,0);
for(int j=1;j<=20;j++)
for(int i=1;i<=cnt;i++)
anc[i][j]=anc[anc[i][j-1]][j-1];
int Q,K,S,last=0;
read(Q),read(K),read(S);
for(int i=1;i<=Q;i++) {
int v0,p0;
read(v0),read(p0);
v0=(v0+K*last-1)%n+1;
p0=(p0+K*last)%(S+1);
for(int j=20;j>=0;j--)
if(anc[v0][j]&&anc_w[anc[v0][j]]>p0)
v0=anc[v0][j];
last=minn[v0];
printf("%d\n",last);
}
_init();
}
return 0;
}

题解 NOI2018 归程的更多相关文章

  1. [洛谷P4768] [NOI2018]归程 (kruskal重构树模板讲解)

    洛谷题目链接:[NOI2018]归程 因为题面复制过来有点炸格式,所以要看题目就点一下链接吧\(qwq\) 题意: 在一张无向图上,每一条边都有一个长度和海拔高度,小\(Y\)的家在\(1\)节点,并 ...

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

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

  3. [NOI2018]归程 kruskal重构树

    [NOI2018]归程 LG传送门 kruskal重构树模板题. 另一篇文章里有关于kruskal重构树更详细的介绍和更板子的题目. 题意懒得说了,这题的关键在于快速找出从查询的点出发能到达的点(即经 ...

  4. NOI2018 D1T1 [NOI2018]归程 解题报告

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

  5. [NOI2018]归程(kruscal重构树)

    [NOI2018]归程 题面太长辣,戳这里 模拟赛上写了一个spfa (关于spfa,它已经死了),然后一个st表水完暴力跑路.考后说是Kruscal重构树或者可持久化并查集???这都是些什么东西.不 ...

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

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

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

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

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

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

  9. 洛谷P4768 [NOI2018]归程 [可持久化并查集,Dijkstra]

    题目传送门 归程 格式难调,题面就不放了. 分析: 之前同步赛的时候反正就一脸懵逼,然后场场暴力大战,现在呢,还是不会$Kruskal$重构树,于是就拿可持久化并查集做. 但是之前做可持久化并查集的时 ...

随机推荐

  1. 20170623_oracle_优化与体系结构

    一般优化技巧 建议不用"*"代替所有列名 删除所有数据用TRUNCATE代替DELETE 用NOT EXISTS 代替NOT IN 用EXISTS代替IN 用EXISTS代替DIS ...

  2. HTTP要点概述:六,HTTP报文

    一,HTTP报文: 用于HTTP交互的信息称为HTTP报文.请求端(客户端)的HTTP报文叫做请求报文,响应端(服务器)的叫做响应报文.HTTP报文本身是由多行(用CR+LF换行)数据构成的字符串文本 ...

  3. Git-flow 一个简单高效的Git工作流

    背景 由于Git的分支比SVN更好管理且更易使用,最近团队从SVN迁移到Git,需要重新规划开发流程,最终确定使用Git-flow工作流,这是目前比较流行的一种分支模型,下面是Git-flow的简易流 ...

  4. iOS核心动画以及UIView动画的介绍

    我们看到很多App带有绚丽狂拽的特效,别出心裁的控件设计,很大程度上提高了用户体验,在增加了实用性的同时,也赋予了app无限的生命力.这些华丽的效果很多都是基于iOS的核心动画原理实现的,本文介绍一些 ...

  5. EasyUI Calendar 日历

    转自:http://www.jeasyui.net/plugins/175.html 通过 $.fn.calendar.defaults 重写默认的 defaults. 日历(calendar)显示允 ...

  6. rspec

    require 'rails_helper' RSpec.describe Jira, '#set_jira_jlist' do it "this sentence is after it& ...

  7. PCB .NET Reactor 加密工具(NecroBit加密技术)

    在PCB行业中,我们使用的软件或脚本绝大多数都用非编译型语言写程序,而从一开始选择这种编程语言,就注定了程序的源码有被曝露风险.我们PCB工程系统用.NET语言编写,C#编译后会被转换为IL代码的中间 ...

  8. c#自定义ORM框架---(泛型&反射&实体类扩展属性<附带通用增、删、查、改>)

    该教材主要是运用到泛型.反射和实体类扩展属性 步骤一.建立扩展属性类 实体类扩展属性要继承Attribute基类完成 [AttributeUsage(AttributeTargets.Property ...

  9. 232 Implement Queue using Stacks 用栈来实现队列

    使用栈来实现队列的如下操作: push(x) -- 将一个元素放入队列的尾部.pop() -- 从队列首部移除元素.peek() -- 返回队列首部的元素.empty() -- 返回队列是否为空.注意 ...

  10. 微信小程序授权 获取用户的openid和session_key【后端使用java语言编写】,我写的是get方式,目的是测试能否获取到微信服务器中的数据,后期我会写上post请求方式。

    在这里给大家分享下我的心得,1.写代码前一定要对整个流程有个了解.我就是因为在先不了解整个过程中去ctrl+c+v他人的博客代码,花费很多无用的时间去处理还不知道能不能跑的起来的代码. 2.本人比较喜 ...