Desant 2 题解

LibreOJ-3614 Luogu-P9040

很好的题。


先不考虑区间,先想 \(l=1,r=n\) 的情况。

考虑 dp,\(f_i\) 表示考虑 \([l,r]\) 的答案。

则容易得到:

\[f_i=\max\left\{f_{i-1}, f_{i-k}+s_i-s_{i-k}\right\},f_0=0 \]

其中 \(s\)\(a\) 的前缀和。

这个转移本身是 \(\Theta(n)\) 的。

遇见这种区间查询 DP 的通常都是动态 DP,但是由于下标跨了 \(k\),矩阵的大小为 \(\Theta(k)\),所以进行如此操作的时间复杂度为 \(\Theta(k^3\log n)\),表现很差。

本题难点在此。

我们看到这个 DP 式子非常工整,灵光一现,唉我给她塞图上。

我们从 \(u\)\(v\) 连长度为 \(w\) 的边表示 \(f_v\) 的转移方程式里有一项为 \(f_u + w\)

突破口出现了!

原题所求的 \([l,r]\) 的答案就是 \(l-1\)\(r\) 的最长路!(注意此处由于 \(l\) 也要参与运算,所以起点为 \(l-1\)


但是新的问题到来了,怎么给这样一个图求两点最短路呢?

显然不能 Johnson,这样比暴力还慢。

显然是要利用这个图的结构。

我们经过一顿梳理发现她长这样。

![](/home/lightningcreeper/Blog/desant 2 题解 1.png)

规规整整的跟个矩形一样。

知道网格求最短路的同学瞬间就懂了。


接下来是个很经典的 trick。

对于一类网格图,我们若要求若干点对间的最短或长路则采用以下算法:

我们考虑把询问离线下来分治。

每次分治面向原网格中的一个子网格。

为了方便我们设她是 \(r\times c\) 的。

\(1^\circ\)\(r>c\),我们按照中间行把她切成两半,对于中间行上每个点 \(p\) 算出其对子矩阵里所有点的最短或长路。(若是 DAG 则可直接 DP),然后枚举所有被这个中间行分开的点对 \(u,v\),将 \(u\)\(v\) 的最短或长路经过 \(p\) 松弛。(因为 \(u\)\(v\) 的最短或长路一定经过 \(p\)

\(2^\circ\) 不然则按照中间列切,同样枚举中间列上的点来计算。

每次把切完的两个小网格分治下去,要把两端点都在。

每次分治 \(O(n\sqrt n)\)

\[T(n)=O(n\sqrt n) + 2T(\cfrac{n}{2}) \]

由主定理,总复杂度 \(O(n\sqrt n)\)


回到这道题。

我们发现还有一些从最顶上指到底下的边,他们可以通过这条边而不需通过中间行。

对于这种情况我们可以额外枚举第一行的每个点,因为经过斜边一定要经过第一行的点。

但是有可能在同一侧的节点的最长路穿下去再慢慢爬上来的情况。

这种情况我们也要给在同一侧的点对统计答案,但是由于只有一次不影响复杂度。

#pragma GCC optimize("Ofast", 3, 2, 1)
#include <bits/stdc++.h>
using namespace std;#define int long long
#define endl '\n'
#define debug(x) cerr << #x << " = " << x << endl
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define gn(u, v) for (int v : G.G[u])
#define pb emplace_back
#define mp make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define pii pair<int, int>
#define vi vector<int>
#define vpii vector<pii>
#define vvi vector<vi>
#define no cout << "NO" << endl
#define yes cout << "YES" << endl
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define tomin(x, y) ((x) = min((x), (y)))
#define tomax(x, y) ((x) = max((x), (y)))
#define ck(mask, i) (((mask) >> (i)) & 1)
#define pq priority_queue
#define FLG (cerr << "Alive!" << endl);constexpr int MAXN = 6e5 + 5;
constexpr int INF = 0x3f3f3f3f3f3f3f3f;
int n, k, q;
int a[MAXN];
vector<vpii> G;
vector<vpii> H;struct Query {int u, v, ans;
};
vector<Query> query;vi num[MAXN];
int x[MAXN], y[MAXN];
int dis[2][MAXN];void get(int start, const vector<vpii> &G, const vector<vpii> &H, int lx, int rx, int ly, int ry, bool typ) {// rep(i, lx, rx) {//     rep(j, ly, ry) {//         dis[typ][num[i][j]] = -INF;//     }// }vi vis;if (typ) {per(j, ry, ly) {per(i, rx, lx) {if (num[i][j] > start && !typ)vis.pb(num[i][j]);if (num[i][j] < start && typ)vis.pb(num[i][j]);}}} else {rep(j, ly, ry) {rep(i, lx, rx) {if (num[i][j] > start && !typ)vis.pb(num[i][j]);if (num[i][j] < start && typ)vis.pb(num[i][j]);}}}dis[typ][start] = 0;for (int u : vis) {if (u == start)continue;dis[typ][u] = -INF;for (auto [v, w] : H[u]) {if (x[v] < lx || x[v] > rx || y[v] < ly || y[v] > ry)continue;// if (u == 200)//     cerr << v << " " << w << " " << typ << endl;if (!typ && v >= start)tomax(dis[typ][u], dis[typ][v] + w);if (typ && v <= start)tomax(dis[typ][u], dis[typ][v] + w);}// cerr << "dis from " << start << " to " << u << " with type " << typ << " is " << dis[typ][u] << endl;// if (u == 200) {//     cerr << dis[typ][u] << endl;// }}
}void solve(int lx, int rx, int ly, int ry, vector<Query> &q) {if (lx > rx || ly > ry || q.empty())return;rep(i, lx, rx) {rep(j, ly, ry) {dis[false][num[i][j]] = dis[true][num[i][j]] = 0;}}if (rx - lx <= ry - ly) {int mid = ly + ry >> 1;vector<Query> l, r, now;for (auto [u, v, ans] : q) {if (y[u] < mid && y[v] < mid) {l.pb(Query{u, v, ans});} else if (y[u] > mid && y[v] > mid) {r.pb(Query{u, v, ans});} else {now.pb(Query{u, v, ans});}}rep(tmp, lx, rx) {int cur = num[tmp][mid];get(cur, G, H, lx, rx, ly, ry, false);get(cur, H, G, lx, rx, ly, ry, true);dis[0][cur] = 0;dis[1][cur] = 0;for (auto& [u, v, ans] : now) {// if (u == 170 && v == 200) {//     cerr << cur << "." << lx << " " << rx << " " << ly << " " << ry << endl;//     cerr << dis[0][u] << " " << dis[1][v] << " " << dis[1][u] << " " << dis[0][v] << endl;// }tomax(ans, max(dis[0][u] + dis[1][v], dis[1][u] + dis[0][v]));// cerr << dis[0][u] << " " << dis[1][u] << " " << dis[0][v] << " " << dis[1][v] << endl;}// for (auto& [u, v, ans] : l) {//     // if (u == 170 && v == 200) {//     //     cerr << lx << " " << rx << " " << ly << " " << ry << endl;//     //     cerr << dis[0][u] + dis[1][v] << " " << dis[1][u] + dis[0][v] << endl;//     // }//     tomax(ans, max(dis[0][u] + dis[1][v], dis[1][u] + dis[0][v]));//     // cerr << dis[0][u] << " " << dis[1][u] << " " << dis[0][v] << " " << dis[1][v] << endl;// }// for (auto& [u, v, ans] : r) {//     // if (u == 170 && v == 200) {//     //     cerr << lx << " " << rx << " " << ly << " " << ry << endl;//     //     cerr << dis[0][u] + dis[1][v] << " " << dis[1][u] + dis[0][v] << endl;//     // }//     tomax(ans, max(dis[0][u] + dis[1][v], dis[1][u] + dis[0][v]));//     // cerr << dis[0][u] << " " << dis[1][u] << " " << dis[0][v] << " " << dis[1][v] << endl;// }}solve(lx, rx, ly, mid - 1, l);solve(lx, rx, mid + 1, ry, r);int i = 0, j = 0, cnt = 0;for (auto& [u, v, ans] : q) {if (y[u] < mid && y[v] < mid) {ans = l[i++].ans;} else if (y[u] > mid && y[v] > mid) {ans = r[j++].ans;} else {ans = now[cnt++].ans;}}} else {int mid = lx + rx >> 1;vector<Query> l, r, now;for (auto [u, v, ans] : q) {if (x[u] < mid && x[v] < mid) {l.pb(Query{u, v, ans});} else if (x[u] > mid && x[v] > mid) {r.pb(Query{u, v, ans});} else {now.pb(Query{u, v, ans});}}rep(tmp, ly, ry) {int cur = num[mid][tmp];get(cur, G, H, lx, rx, ly, ry, false);get(cur, H, G, lx, rx, ly, ry, true);dis[0][cur] = 0;dis[1][cur] = 0;for (auto& [u, v, ans] : now) {// if (u == 170 && v == 200) {//     cerr << cur << " " << lx << " " << rx << " " << ly << " " << ry << endl;//     cerr << dis[0][u] << " " << dis[1][v] << " " << dis[1][u] << " " << dis[0][v] << endl;// }tomax(ans, max(dis[0][u] + dis[1][v], dis[1][u] + dis[0][v]));}// for (auto& [u, v, ans] : l) {//     tomax(ans, max(dis[0][u] + dis[1][v], dis[1][u] + dis[0][v]));// }// for (auto& [u, v, ans] : r) {//     tomax(ans, max(dis[0][u] + dis[1][v], dis[1][u] + dis[0][v]));// }}if (lx == 1 && rx == k) {rep(tmp, ly, ry) {int cur = num[lx][tmp];get(cur, G, H, lx, rx, ly, ry, false);get(cur, H, G, lx, rx, ly, ry, true);dis[0][cur] = 0;dis[1][cur] = 0;for (auto& [u, v, ans] : now) {// if (u == 170 && v == 200) {//     cerr << cur << " " << lx << " " << rx << " " << ly << " " << ry << endl;// cerr << dis[0][u] << " " << dis[1][v] << " " << dis[1][u] << " " << dis[0][v] << endl;// }tomax(ans, max(dis[0][u] + dis[1][v], dis[1][u] + dis[0][v]));}for (auto& [u, v, ans] : l) {tomax(ans, max(dis[0][u] + dis[1][v], dis[1][u] + dis[0][v]));}for (auto& [u, v, ans] : r) {tomax(ans, max(dis[0][u] + dis[1][v], dis[1][u] + dis[0][v]));}}}solve(lx, mid - 1, ly, ry, l);solve(mid + 1, rx, ly, ry, r);int i = 0, j = 0, cnt = 0;for (auto& [u, v, ans] : q) {if (x[u] < mid && x[v] < mid) {tomax(ans, l[i++].ans);} else if (x[u] > mid && x[v] > mid) {tomax(ans, r[j++].ans);} else {tomax(ans, now[cnt++].ans);}}}
}signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin >> n >> k >> q;int tmp = (n / k + 1) * k - 1;rep(i, 1, n)cin >> a[i];rep(i, 1, tmp)a[i] += a[i - 1];G.resize(tmp + 1);H.resize(tmp + 1);rep(i, 1, tmp) {G[i - 1].pb(mp(i, 0));H[i].pb(mp(i - 1, 0));if (i >= k)G[i - k].pb(mp(i, a[i] - a[i - k])),H[i].pb(mp(i - k, a[i] - a[i - k]));}query.resize(q);rep(i, 0, q - 1) {cin >> query[i].u >> query[i].v;query[i].u--;query[i].ans = 0;}rep(i, 1, k) {num[i].resize(n / k + 2);}rep(i, 0, (n / k + 1) * k - 1) {num[i % k + 1][i / k + 1] = i;x[i] = i % k + 1;y[i] = i / k + 1;}// rep (i, 0, n) {//     for (auto [v, w] : G[i]) {//         cerr << i << " " << v << " " << w << endl;//     }// }solve(1, k, 1, n / k + 1, query);// cerr << x[170] << " " << y[170] << " " << x[200] << " " << y[200] << endl;rep(i, 0, q - 1)cout << query[i].ans << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/870975.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【洛谷训练记录】【LGR-213-Div.4】洛谷入门赛 #31

训练情况赛后反思 模拟题差点红温,差一道字符串模拟题AK A题 问一个数 \(a\) 加多少后的个位数变成 \(b\),取出 \(a\) 的个位数,再用 \(b\) 去减,如果小于零答案再加十。 #include <bits/stdc++.h> // #define int long long #define endl \nusing namespace std;voi…

WSL2配置代理

1、关闭梯子 2、设置为mirrored模式该设置会生成 C:/Users//.wslconfig【可选】修改.wslconfig文件内容如下 [experimental] autoMemoryReclaim=gradual networkingMode=mirrored dnsTunneling=true firewall=true autoProxy=true3、打开cmd并执行wsl --shutdown 4、重新启动…

【MySQL架构】图解

你是一个程序员,你做了一个网站应用,站点里的用户数据,需要存到某个地方,方便随时读写。 很容易想到可以将数据存到文件里。 但如果数据量很大,想从大量文件数据中查找某部分数据,并更新,是一件很痛苦的事情。 那么问题就来了,有办法可以解决这个问题吗? 好办,没有什…

2025 郑州一测 T18: 双变量问题探讨

2025 高考加把劲 /qtContent已知函数 \(f(x) = \log_a x(a>0, a\neq 1)\), \(y = f(x)\) 关于 \(y=x\) 对称的函数记为 \(g(x)\). (I) 若 \(a>1\), 方程 \(f(x)-g(x)=0\) 有且仅有一个实数解, 求 \(a\) 的值. (II) 讨论方程 \(g(x) = x_a = 0\) 在 \((0, +\infty)\) 上实…

笑死

哈哈哈哈哈笑死这个中国银行的标志出现的恰到好处,我还以为是什么标识

C#数据结构与算法入门实战指南

前言 在编程领域,数据结构与算法是构建高效、可靠和可扩展软件系统的基石。它们对于提升程序性能、优化资源利用以及解决复杂问题具有至关重要的作用。今天大姚分享一些非常不错的C#数据结构与算法实战教程,希望可以帮助到有需要的小伙伴。 C#经典十大排序算法 主要讲解C#经典…

29. 数据库操作

一、SQL与数据库数据库 (database)是统一管理的、有组织的、可共享的大量数据的集合。数据库将数据存储在一个或多个表格中,管理这个数据库的软件称为 数据库管理系统(database management system, DBMS)。数据库不是针对具体的应用程序,而是立足于数据本身的管理,它将所…

用Mermaid画图

1、用Mermaid画图 mermaid.md TyporaPortable.rar mermaid.zip 目录1 Mermaid是什么1.1 概述1.2 网址官网地址:Github地址:图形图形几种图形名字节点与无名字节点设置样式:style, classDef, class, :::线条图形连线(--)及注释(%%)线条样式实线与虚线箭头实线与粗实线及箭头延…

【RabbitMQ】图解

你是一个程序员,假设你维护了两个服务 A 和 B。 A 服务负责转发用户请求到 B 服务,B 服务是个算法服务,GPU 资源有限,当请求量大到 B 服务处理不过来的时候,希望能优先处理会员用户的请求。 那么问题就来了,如果普通用户和会员用户同时发起请求,怎样才能做到会员优先呢?…

THREE.js学习笔记8——Textures

这个小节主要学习纹理,Texture 纹理是覆盖几何形状表面的图像,不同类型的纹理具有多种不同的效果。 这些纹理(尤其是金属性和粗糙度)遵循PBR原则基于物理的渲染 许多技术往往遵循现实生活中的方向以获得现实的结果 成为现实渲染的标准 许多软件、引擎和库都在使用它如何加载…

快速傅里叶变换总结

基本概念 对于求和式 \(\sum a_ix^i\),如果是有限项相加,称为多项式,记作 \[f(x)=\sum_{i=0}^n a_ix^i。 \]其中最高次项的次数为 \(n\),为 \(n\) 次多项式。 用 \(n+1\) 个点可以唯一地确定一个 \(n\) 次多项式,这一过程可以参考 拉格朗日插值。 引入 给定多项式 \(f(x),…

寒假学习1

老年人评估系统 初步整理web端思路先写了第一张信息表并搭建基本框架并编写了老年人信息添加功能