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