|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 zhangjinxuan 于 2024-3-6 08:52 编辑
Never gonna give you up. Never gonna let you down.
题目链接:https://www.luogu.com.cn/problem/P9912
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, Q, a[200001], ans[200001], rem[200001];
map<int, vector<int>> pos;
struct Query {
int l, r, x, id;
} q[200001];
map<int, vector<Query>> qs;
struct Info {
int tot, lh, rh; // 最左边有没有块,最右边有没有块
};
Info add(const Info a, const Info b) { // 注意该运算不满足交换律
if (a.tot + a.lh + a.rh == -3) return b;
if (b.tot + b.lh + b.rh == -3) return a;
return {a.tot + b.tot - (a.rh && b.lh), a.lh, b.rh};
}
namespace SGT {
Info res[2000003];
#define ls(i) (i << 1)
#define rs(i) (i << 1 | 1)
void build(int i, int l, int r) {
if (l == r) return res[i] = {1, 1, 1}, void();
int mid = (l + r) / 2; build(ls(i), l, mid); build(rs(i), mid + 1, r);
res[i] = add(res[ls(i)], res[rs(i)]);
}
void update(int i, int l, int r, int qp) {
if (l > qp || r < qp) return; int mid = (l + r) / 2;
if (l == r && l == qp) return res[i] = {0, 0, 0}, void();
update(ls(i), l, mid, qp); update(rs(i), mid + 1, r, qp);
res[i] = add(res[ls(i)], res[rs(i)]);
}
Info query(int i, int l, int r, int ql, int qr) {
if (l > qr || r < ql) return {-1, -1, -1};
//printf("%d %d %d %d %d\n", l, r, res[i].tot, res[i].lh, res[i].rh);
if (l >= ql && r <= qr) return res[i];
int mid = (l + r) / 2;
return add(query(ls(i), l, mid ,ql, qr), query(rs(i), mid + 1, r, ql, qr));
}
}
signed main() {
scanf("%lld%lld", &n, &Q);
vector<int> qss;
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
pos[a[i]].push_back(i);
qss.push_back(a[i]);
}
sort(qss.begin(), qss.end());
auto enit = unique(qss.begin(), qss.end());
int minv = 1ll << 60;
for (int i = 1; i <= Q; ++i) {
scanf("%lld%lld%lld", &q[i].l, &q[i].r, &q[i].x);
if (q[i].x < qss[0]) q[i].x = -1;
else q[i].x = qss[min((std::vector<long long>::size_type)(lower_bound(qss.begin(), enit, q[i].x + 1) - qss.begin() - 1), qss.size() - 1)];
q[i].id = i; qs[q[i].x].push_back(q[i]);
minv = min(minv, q[i].x);
}
for (int i = 1; i <= n; ++i) {
if (a[i] < minv) pos[minv].push_back(i);
}
SGT::build(1, 1, n);
for (auto i : qs) {
for (auto j : pos[i.first]) {
if (rem[j]) continue;
rem[j] = 1;
SGT::update(1, 1, n, j);
}
for (auto j : i.second) {
Info tmp = SGT::query(1, 1, n, j.l, j.r);
ans[j.id] = tmp.tot;
//printf("ans: %lld, %lld, %lld, %lld\n", j.id, tmp.tot, tmp.lh, tmp.rh);
}
}
for (int i = 1; i <= Q; ++i) printf("%lld\n", ans[i]);
}
这是一个离线算法,大体思路如下:
- 首先所有的询问的 x 参数,把 x 重新赋值为在 a 序列中比他小于等于的最大值,如果不存在就改成 0。
- 然后按照询问参数 x 从小到大模拟涨水,对于每一次涨水,看看哪些点被淹没了,在线段树中作出对应的修改。
- 最后查询区间,还原询问。
线段树记录的节点表示目前的岛屿组成极大未淹没连续子段的情况,tot 表示总数,lh 表示这个区间最左边的岛屿是否被淹没,rh 表示这个区间最右边的岛屿是否被淹没。
严重怀疑是第一步写错了,或者是线段树 query 返回 {-1, -1, -1} 这个地方。
第一次尝试写代码,结果全是错的。
我这代码都超时,你那肯定超
不过这代码除了tle就是ac
代码应该没有问题,接下来看看要如何提高代码效率了
这洛谷最恶心的一点就是,他只告诉你错了,但是不告诉你在哪个数据上错了
这还调试个球
你只能去猜自己代码中可能的问题,没法调试
如果可以,换一个刷题网站吧
这洛谷太tm垃圾了
/*
#include <iostream>
using std::cin, std::cout, std::endl;
int find(int n, const int *h, int l, int r, int x) {
--l, --r;
int count = 0;
while(true) {
while(l <= r) if(h[l++] > x) goto e;
return count;
e: while(l <= r) if(h[l++] <= x) break;
++count;
}
}
int main() {
int n, q; cin >> n >> q;
int h[n]; for(int i = 0; i < n; ++i) cin >> h[i];
for(int i = 0; i < q; ++i) {
int l, r, x;
cin >> l >> r >> x;
int count = find(n, h, l, r, x);
cout << count << endl;
}
return 0;
}
*/
/*
#include <iostream>
using std::cin, std::cout, std::endl;
int n, q, h[200000], l, r, x;
int count, i;
void find() {
--l, --r;
count = 0;
while(true) {
while(l <= r) if(h[l++] > x) goto e;
return;
e: while(l <= r) if(h[l++] <= x) break;
++count;
}
}
int main() {
cin >> n >> q;
for(i = 0; i < n; ++i) cin >> h[i];
for(i = 0; i < q; ++i) {
cin >> l >> r >> x;
find(); cout << count << endl;
}
return 0;
}
*/
#include <cstdio>
using std::scanf, std::printf;
int n, q, h[200000], l, r, x;
int count, i;
__attribute((always_inline)) inline void find() {
--l, --r;
count = 0;
while(true) {
while(l <= r) if(h[l++] > x) goto e;
return;
e: while(l <= r) if(h[l++] <= x) break;
++count;
}
}
int main() {
scanf("%d%d", &n, &q);
for(i = 0; i < n; ++i) scanf("%d", &h[i]);
for(i = 0; i < q; ++i) {
scanf("%d%d%d", &l, &r, &x);
find(); printf("%d\n", count);
}
return 0;
}
|
|