并不会写Kruskal重构树,两个$log$跑得比较卡。

首先考虑一下没有强制在线的要求怎么办,有一个比较容易想到的做法就是先跑一遍最短路,然后把所有边按照海拔从大到小排序,把所有询问的海拔也从大到小排序,然后对于每一个询问$(x, h)$把所有海拔高于$h$的边都连上,然后看一看点$x$的能到达的点中离$1$距离最小的点是多少。

这就是一个并查集可以维护的东西了。

强制在线怎么办……直接大力把这个并查集可持久化……就没了。

时间复杂度$O(nlog^2n)$。

Code:

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair <int, int> pin; const int N = 2e5 + ;
const int M = 5e5 + ; int testCase, n, m, qn, tot, head[N], dis[N];
int numCnt, in[M], ed[M], pos[M];
bool vis[N]; struct Edge {
int to, nxt, val;
} e[M << ]; inline void add(int from, int to, int val) {
e[++tot].to = to;
e[tot].val = val;
e[tot].nxt = head[from];
head[from] = tot;
} struct Pathway {
int x, y, val, h, id;
} path[M]; bool cmp(const Pathway &u, const Pathway &v) {
return u.h < v.h;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} priority_queue <pin> Q;
void dij() {
memset(dis, 0x3f, sizeof(dis));
memset(vis, , sizeof(vis));
Q.push(pin(dis[] = , ));
for(; !Q.empty(); ) {
int x = Q.top().second; Q.pop();
if(vis[x]) continue;
vis[x] = ;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(dis[y] > dis[x] + e[i].val) {
dis[y] = dis[x] + e[i].val;
Q.push(pin(-dis[y], y));
}
}
}
} inline int min(int x, int y) {
return x > y ? y : x;
} inline void swap(int &x, int &y) {
int t = x; x = y; y = t;
} namespace PUfs {
struct Node {
int lc, rc, ufs, dis, dep;
} s[N * ];
int root[M], nodeCnt = 0LL; #define lc(p) s[p].lc
#define rc(p) s[p].rc
#define ufs(p) s[p].ufs
#define dis(p) s[p].dis
#define dep(p) s[p].dep
#define mid ((l + r) >> 1) inline void clear(int p) {
lc(p) = rc(p) = ufs(p) = dis(p) = dep(p) = ;
} void build(int &p, int l, int r, int type) {
p = ++nodeCnt;
if(l == r) {
ufs(p) = l, dep(p) = ;
if(!type) dis(p) = ;
else dis(p) = dis[l];
return;
} build(lc(p), l, mid, type);
build(rc(p), mid + , r, type);
} void modify(int &p, int l, int r, int x, int nowUfs, int nowDis, int pre) {
p = ++nodeCnt;
if(l == r) {
ufs(p) = nowUfs, dis(p) = nowDis, dep(p) = dep(pre);
return;
} lc(p) = lc(pre), rc(p) = rc(pre);
if(x <= mid) modify(lc(p), l, mid, x, nowUfs, nowDis, lc(pre));
else modify(rc(p), mid + , r, x, nowUfs, nowDis, rc(pre));
} void mDis(int &p, int l, int r, int x, int nowDis, int pre) {
p = ++nodeCnt;
if(l == r) {
ufs(p) = ufs(pre), dep(p) = dep(pre), dis(p) = nowDis;
return;
} lc(p) = lc(pre), rc(p) = rc(pre);
if(x <= mid) mDis(lc(p), l, mid, x, nowDis, lc(pre));
else mDis(rc(p), mid + , r, x, nowDis, rc(pre));
} void add(int p, int l, int r, int x) {
if(l == r) {
++dep(p);
return;
} if(x <= mid) add(lc(p), l, mid, x);
else add(rc(p), mid + , r, x);
} int query(int p, int l, int r, int x) {
if(l == x && x == r) return p; if(x <= mid) return query(lc(p), l, mid, x);
else return query(rc(p), mid + , r, x);
} int find(int now, int x) {
int f = query(now, , n, x);
if(s[f].ufs == x) return f;
else return find(now, s[f].ufs);
} inline void merge(int k, int x, int y) {
root[k] = root[k + ];
int fx = find(root[k], x), fy = find(root[k], y);
if(s[fx].ufs == s[fy].ufs) return;
if(s[fx].dep > s[fy].dep) swap(fx, fy);
int dis = min(s[fx].dis, s[fy].dis);
modify(root[k], , n, s[fx].ufs, s[fy].ufs, dis, root[k + ]);
if(dis != s[fy].dis) mDis(root[k], , n, s[fy].ufs, dis, root[k]);
if(s[fx].dep == s[fy].dep) add(root[k], , n, s[fy].ufs);
} #undef mid } using namespace PUfs; inline void prework() {
for(int i = ; i <= nodeCnt; i++) clear(i);
nodeCnt = ; memset(root, , sizeof(root));
build(root[m + ], , n, );
build(root[], , n, );
} inline int bfind(int val) {
int ln = , rn = numCnt, mid, res;
for(; ln <= rn; ) {
mid = (ln + rn) / ;
if(in[mid] <= val) ln = mid + , res = mid;
else rn = mid - ;
}
return res;
} int main() {
// freopen("return.in", "r", stdin);
// freopen("return.out", "w", stdout); for(read(testCase); testCase--; ) {
tot = numCnt = ; memset(head, , sizeof(head)); read(n), read(m);
for(int i = ; i <= m; i++) {
read(path[i].x), read(path[i].y), read(path[i].val), read(path[i].h);
in[++numCnt] = path[i].h;
path[i].id = i;
add(path[i].x, path[i].y, path[i].val), add(path[i].y, path[i].x, path[i].val);
} sort(in + , in + + numCnt);
numCnt = unique(in + , in + + numCnt) - in - ; /* for(int i = 1; i <= numCnt; i++)
printf("%d ", in[i]);
printf("\n"); */ for(int i = ; i <= m; i++)
path[i].h = lower_bound(in + , in + + numCnt, path[i].h) - in; dij(); /* for(int i = 1; i <= n; i++)
printf("%d ", dis[i]);
printf("\n"); */ prework();
sort(path + , path + + m, cmp); /* printf("\n");
for(int i = 1; i <= m; i++)
printf("%d %d %d %d\n", path[i].x, path[i].y, path[i].val, path[i].h); */ for(int i = m; i >= ; i--) {
merge(i, path[i].x, path[i].y);
if(path[i].h != path[i - ].h) ed[path[i].h] = i;
} /* for(int i = 1; i <= numCnt; i++)
printf("%d ", ed[i]);
printf("\n"); */ for(int i = ; i < numCnt; i++) pos[i] = ed[i + ];
pos[numCnt] = m + ; /* for(int i = 1; i <= numCnt; i++)
printf("%d ", pos[i]);
printf("\n"); */ /* for(int j = 1; j <= n; j++)
printf("%d ", s[query(root[m + 1], 1, n, j)].dis);
printf("\n"); */ /* for(int i = 1; i <= numCnt; i++) {
printf("%d: ", i);
for(int j = 1; j <= n; j++)
printf("%d ", s[query(root[pos[i]], 1, n, j)].ufs);
printf("\n");
} for(int i = 1; i <= numCnt; i++) {
printf("%d: ", i);
for(int j = 1; j <= n; j++)
printf("%d ", s[query(root[pos[i]], 1, n, j)].dis);
printf("\n");
} */ /* for(int i = 1; i <= numCnt; i++)
printf("%d ", pos[i]);
printf("\n"); */ // in[++numCnt] = path[m].h + 1; int K, S, ans = ;
read(qn), read(K), read(S);
for(int x, h; qn--; ) {
read(x), read(h);
x = (x + K * ans - ) % n + , h = (h + K * ans) % (S + );
int rt = bfind(h);
rt = pos[rt];
rt = find(root[rt], x);
printf("%d\n", ans = s[rt].dis);
}
}
return ;
}

缅怀$spfa$。

Luogu 4768 [NOI2018]归程的更多相关文章

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

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

  2. Luogu P4768 [NOI2018]归程

    题目链接 \(Click\) \(Here\) \(Kruskal\)重构树的好题.想到的话就很好写,想不到乱搞的难度反而相当高. 按照点的水位,建出来满足小根队性质的\(Kruskal\)重构树,这 ...

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

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

  4. [NOI2018]归程 kruskal重构树

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

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

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

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

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

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

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

  8. 题解 NOI2018 归程

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

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

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

随机推荐

  1. 【Flask】SelectedField 同步数据库

    ## 如果不加入__init__函数会导致,SelectedField表单生成只有里面的内容不会和数据库同步(即数据库添加,删除字段时表单中数据项和初始化时一致.下一次重启app是才会同步) clas ...

  2. CSS3自定义下拉框菜单

    在线演示 本地下载

  3. svn及git使用笔记

    这周发生好几件大事: 谷歌发布SHA-1安全加密碰撞实例 Cloudflare 泄露网络会话中的加密数据 linux内核漏洞 CVE-2017-6074 加密在网络中越来越受关注,目前github的提 ...

  4. 中美贸易战再次开启,世界两极化进程正在加快形成!..... Copyright: 1688澳洲新闻网 Read more at: https://www.1688.com.au/world/international/2018/06/17/369368/

    中美贸易战再次开启,世界两极化进程正在加快形成! https://www.1688.com.au/world/international/2018/06/17/369368/

  5. Office文件的奥秘——.NET平台下不借助Office实现Word、Powerpoint等文件的解析

    Office文件的奥秘——.NET平台下不借助Office实现Word.Powerpoint等文件的解析 分类: 技术 2013-07-26 15:38 852人阅读 评论(0) 收藏 举报 Offi ...

  6. 源码安装postgres10 in centos6.4

    文件夹路径 程序目录 /usr/pgsql 数据目录/usr/local/pgdata 准备工作 获得源码 mkdir /opt/soft_bak cd /opt/soft_bak wget http ...

  7. HihoCoder1663双阶乘的末尾数字([Offer收割]编程练习赛40)(暴力||数学)

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定正整数x和k,判断是否存在正整数1 ≤ y ≤ x使得x与y同奇偶且(x!!)/(y!!)的个位数字为k. 其中x!! ...

  8. LOJ2305 「NOI2017」游戏

    「NOI2017」游戏 题目背景 狂野飙车是小 L 最喜欢的游戏.与其他业余玩家不同的是,小 L 在玩游戏之余,还精于研究游戏的设计,因此他有着与众不同的游戏策略. 题目描述 小 L 计划进行$n$场 ...

  9. ACM学习历程—HDU5422 Rikka with Graph(贪心)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  10. photonView 空指针异常

    1.OBJ上要有PhotonView 脚本 2.PhotonNetwork.Instantiate方法初始化出来OBJ OBJ 预制体要放在Resources文件夹下 PhotonNetwork.In ...