|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
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;
- }
复制代码
|
|