Luogu 4768 [NOI2018]归程
并不会写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]归程的更多相关文章
- Luogu P4768 [NOI2018]归程(Dijkstra+Kruskal重构树)
P4768 [NOI2018]归程 题面 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 \(n\) 个节点. \(m\) 条边的无向连通图(节点的编 ...
- Luogu P4768 [NOI2018]归程
题目链接 \(Click\) \(Here\) \(Kruskal\)重构树的好题.想到的话就很好写,想不到乱搞的难度反而相当高. 按照点的水位,建出来满足小根队性质的\(Kruskal\)重构树,这 ...
- [luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树)
[luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树) 题面 题面较长,这里就不贴了 分析 看到不能经过有积水的边,即不能经过边权小于一定值的边,我们想到了kru ...
- [NOI2018]归程 kruskal重构树
[NOI2018]归程 LG传送门 kruskal重构树模板题. 另一篇文章里有关于kruskal重构树更详细的介绍和更板子的题目. 题意懒得说了,这题的关键在于快速找出从查询的点出发能到达的点(即经 ...
- [洛谷P4768] [NOI2018]归程 (kruskal重构树模板讲解)
洛谷题目链接:[NOI2018]归程 因为题面复制过来有点炸格式,所以要看题目就点一下链接吧\(qwq\) 题意: 在一张无向图上,每一条边都有一个长度和海拔高度,小\(Y\)的家在\(1\)节点,并 ...
- NOI2018 D1T1 [NOI2018]归程 解题报告
P4768 [NOI2018]归程 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 \(n\) 个节点.\(m\) 条边的无向连通图(节点的编号从 \ ...
- BZOJ_5415_[Noi2018]归程_kruscal重构树+倍增+最短路
BZOJ_5415_[Noi2018]归程_kruscal重构树+倍增 Description www.lydsy.com/JudgeOnline/upload/noi2018day1.pdf 好久不 ...
- 题解 NOI2018 归程
题解 NOI2018 归程 题意 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l, ...
- [NOI2018]归程(kruscal重构树)
[NOI2018]归程 题面太长辣,戳这里 模拟赛上写了一个spfa (关于spfa,它已经死了),然后一个st表水完暴力跑路.考后说是Kruscal重构树或者可持久化并查集???这都是些什么东西.不 ...
随机推荐
- 【Flask】SelectedField 同步数据库
## 如果不加入__init__函数会导致,SelectedField表单生成只有里面的内容不会和数据库同步(即数据库添加,删除字段时表单中数据项和初始化时一致.下一次重启app是才会同步) clas ...
- CSS3自定义下拉框菜单
在线演示 本地下载
- svn及git使用笔记
这周发生好几件大事: 谷歌发布SHA-1安全加密碰撞实例 Cloudflare 泄露网络会话中的加密数据 linux内核漏洞 CVE-2017-6074 加密在网络中越来越受关注,目前github的提 ...
- 中美贸易战再次开启,世界两极化进程正在加快形成!..... 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/
- Office文件的奥秘——.NET平台下不借助Office实现Word、Powerpoint等文件的解析
Office文件的奥秘——.NET平台下不借助Office实现Word.Powerpoint等文件的解析 分类: 技术 2013-07-26 15:38 852人阅读 评论(0) 收藏 举报 Offi ...
- 源码安装postgres10 in centos6.4
文件夹路径 程序目录 /usr/pgsql 数据目录/usr/local/pgdata 准备工作 获得源码 mkdir /opt/soft_bak cd /opt/soft_bak wget http ...
- HihoCoder1663双阶乘的末尾数字([Offer收割]编程练习赛40)(暴力||数学)
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定正整数x和k,判断是否存在正整数1 ≤ y ≤ x使得x与y同奇偶且(x!!)/(y!!)的个位数字为k. 其中x!! ...
- LOJ2305 「NOI2017」游戏
「NOI2017」游戏 题目背景 狂野飙车是小 L 最喜欢的游戏.与其他业余玩家不同的是,小 L 在玩游戏之余,还精于研究游戏的设计,因此他有着与众不同的游戏策略. 题目描述 小 L 计划进行$n$场 ...
- ACM学习历程—HDU5422 Rikka with Graph(贪心)
Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...
- photonView 空指针异常
1.OBJ上要有PhotonView 脚本 2.PhotonNetwork.Instantiate方法初始化出来OBJ OBJ 预制体要放在Resources文件夹下 PhotonNetwork.In ...