模板题
从前有个人名叫 WNB,他有着天才般的记忆力,他珍藏了许多许多的宝藏。
在他离世之后留给后人一个难题(专门考验记忆力的啊!),如果谁能轻松回答出这个问题,便可以继承他的宝藏。
题目是这样的:给你一大串数字(编号为 1 到N,大小可不一定哦!),在你看过一遍之后,它便消失在你面前,随后问题就出现了,给你 M 个询问,每次询问就给你两个数字A,B,要求你瞬间就说出属于 A 到 B 这段区间内的最大数。
一天,一位美丽的姐姐从天上飞过,看到这个问题,感到很有意思(主要是据说那个宝藏里面藏着一种美容水,喝了可以让这美丽的姐姐更加迷人),于是她就竭尽全力想解决这个问题。
但是,她每次都以失败告终,因为这数字的个数是在太多了!
于是她请天才的你帮他解决。如果你帮她解决了这个问题,可是会得到很多甜头的哦!
输入格式
第一行一个整数 N 表示数字的个数。
接下来一行为 N 个数,表示数字序列。
第三行读入一个 M,表示你看完那串数后需要被提问的次数。
接下来 M 行,每行都有两个整数 A,B。
输出格式
输出共 M 行,每行输出一个数,表示对一个问题的回答。
数据范围
1≤N≤2×10^5,
1≤M≤10^4,
1≤A≤B≤N。
输入样例:
6
34 1 8 123 3 2
4
1 2
1 5
3 4
2 3
输出样例:
34
123
123
8
代码
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 2e5 + 10, M = 18;
int dp[N][M], w[N];
int n, m;
int A, B;
void init()
{
for(int j = 0;j < M;j ++){
for(int i = 1;i + (1 << j) - 1 <= n;i ++){
if(!j) dp[i][j] = w[i];
else dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
}
}
}
void query(int A, int B)
{
int len = B - A + 1;
int k = log(len) / log(2);
cout << max(dp[A][k], dp[B - (1 << k) + 1][k]) << endl;
}
int main()
{
cin >> n;
for(int i = 1;i <= n;i ++) cin >> w[i];
init();
cin >> m;
while(m --){
cin >> A >> B;
query(A, B);
}
return 0;
}
应用
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
题目描述
小Z生活在树上,这一天他计划将他的住所向下迁移。
现在给出一颗有 n 个结点且以 1 结点为根的树,树上的每一条边都有一个权值。有q 个询问,每一次询问给出两个数 u 和 d,其中 u 表示小Z目前居住的结点,d 表示小Z计划向下移动的次数。小Z希望向下移动的路径上的边的权值和最大,请你输出能得到的最大权值。如果没有合法路径,输出 −1。
输入描述:
第一行包含一个整数 n(1≦n≦105),表示树的结点数。 接下来的 n−1n-1n−1 行,每行包含三个整数 a,b,w(1≦a,b≦n;1≦w≦109),表示结点 a 和结点 b 之间有一条权值为 w 的边 。 接下来一行输入一个整数 q(1≦q≦105),表示询问次数。 接下来的 q 行,每行包含两个整数 u,d(1≦u≦n;1≦d≦n),表示小Z目前居住的结点和计划向下移动的次数。
输出描述:
对于每一个询问,输出小Z能够得到的最大权值和。如果没有合法路径,输出 −1。
示例1
输入
5 1 2 3 1 3 5 2 4 2 2 5 1 3 1 2 2 1 3 2
输出
5 2 -1
说明
第一个查询中,从结点 1 向下移动2 次,路径为 41→2→4,权值和为3 + 2 = 53+2=5。 第二个查询中,从结点 2 向下移动 1 次,路径为 42→4,权值和为 2。 第三个查询中,从结点 3 向下移动 2 次没有合法路径,输出 −1。
相当难的一道题,用到的算法:dfs序,RMQ打表, 前缀和,二分。而且很卡空间,前面的算法不仅要掌握还要非常非常熟练,不然就算想到思路了,代码也写不出来
首先就是要知道dfs序有什么用, 比如给定树上两个点 u, v 如果要判断 v 是否是 u 的子节点,那么dfs序要满足 lu < lv < rv < ru。用 dep[u] + d 表示跳到的层,如果超出了直接 -1 即可, 没超出就二分找子节点,然后用RMQ预处理好的表去查询即可
代码
#include <iostream>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
#define ll long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
int dep[N], dfn[N], l[N], r[N];
ll val[N];
void solve()
{
int n;
cin >> n;
vector<vector<PII>> e(n + 1);
for (int i = 1, u, v, w; i < n; i++) {
cin >> u >> v >> w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
vector<vector<int>> p(n + 1);
int tot = 0;
dep[1] = 1;
auto dfs = [&](auto &&self, int u, int fa) -> void {
dfn[u] = ++tot;
l[u] = tot;
for (auto [v, w] : e[u]) {
if (v == fa) continue;
dep[v] = dep[u] + 1;
p[dep[v]].push_back(v);
val[v] = val[u] + w;
self(self, v, u);
}
r[u] = tot;
};
auto cmp = [&](int A, int B) -> bool {
return dfn[A] < dfn[B];
};
dfs(dfs, 1, 0);
for (int i = 1; i <= n; i++) {
sort(p[i].begin(), p[i].end(), cmp);
}
vector<vector<vector<ll>>> dp(n + 1);
for (int k = 1; k <= n; k++) {
if (p[k].size() == 0) continue;
dp[k].resize(p[k].size() + 1);
int len = log2(p[k].size()) + 1;
for (int z = 0; z < p[k].size(); z++) {
dp[k][z].resize(len);
dp[k][z][0] = val[p[k][z]];
}
for (int j = 1; j < len; j++) {
for (int i = 0; i < p[k].size() && i + (1 << j) - 1 < p[k].size(); i++) {
dp[k][i][j] = max(dp[k][i][j - 1], dp[k][i + (1 << (j - 1))][j - 1]);
}
}
}
// 查询区间最大值
auto ask = [&](int l, int r, int u, int deep) -> ll {
int len = r - l + 1;
int k = log2(len);
return max(dp[deep][l][k], dp[deep][r - (1 << k) + 1][k]);
};
int m;
cin >> m;
while (m--) {
int u, d;
cin >> u >> d;
int nd = dep[u] + d; // 目标深度
if (nd > n || p[nd].size() == 0) {
cout << "-1\n";
continue;
}
int l1 = 0, r1 = p[nd].size() - 1;
int ansl = -1, ansr = -1;
while (l1 < r1) {
int mid = (l1 + r1) >> 1;
if (dfn[p[nd][mid]] >= l[u]) r1 = mid;
else l1 = mid + 1;
}
if (dfn[p[nd][l1]] >= l[u]) ansl = l1;
if (ansl == -1) {
cout << "-1\n";
continue;
}
int l2 = 0, r2 = p[nd].size() - 1;
while (l2 < r2) {
int mid = (l2 + r2 + 1) >> 1;
if (dfn[p[nd][mid]] <= r[u]) l2 = mid;
else r2 = mid - 1;
}
if (dfn[p[nd][l2]] <= r[u]) ansr = l2;
if (ansr == -1 || ansl > ansr) {
cout << "-1\n";
continue;
}
cout << ansl << " " << ansr << endl;
cout << ask(ansl, ansr, u, nd) - val[u] << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}
加油