ABC344G 题解

题意

给定 N 个二维平面上的点 (Xi,Yi)Q 组询问,每组询问给出一条直线 Y=AiX+Bi,问有多少个点在直线上方(或者在直线上)。也就是询问有多少个 (Xi,Yi),满足 YiAj×Xi+Bj

题解

首先这个式子是 A×X+BY,移项得 A×X+YB。假设每组询问的 A 相等,那么把 (X,Y)A×X+Y 排序,然后二分答案即可。而对于 A 不同的情况,沿用刚才的方法,考虑维护这个排序后的序列(记为 B)。

这个序列显然不能在线维护,考虑离线。离线后对 Q 个询问按 A 从大到小排序,思考 A 变小后,序列会发生什么变化。也就是对于两个点对 (Xi,Yi),(Xj,Yj) 且在序列 B 中有 i<j,原本存在关系 A1Xi+YiA1Xj+Yj,移项得 A1(XiXj)+(YiYj)0。在 A1 变成 A2 ( A2A1 ) 后,如果 i 被放到 j 的后面,就存在 A2(XiXj)+(YiYj)0,孤立 A2 之后得到 A2YiYjXiXj,而 YiYjXiXj 其实就是 (Xi,Yi)(Xj,Yj) 两点所连直线的斜率。

然后这道题就可以做了。首先将询问按 A=+ 时的 AXi+Yi 排序,其实就是将 Xi 按从大到小排序,Xi 相等时将 Y 从小到大。接着开一个小根堆存序列 B 中相邻两点的斜率。一个一个询问往后扫,每次扫到一个新询问,看一下小根堆存的斜率里面有没有可以被更新顺序的。然后对 Bi 二分就行了。复杂度 O(QlogN+N2logN),这题时限 10s 可以过。

code:

#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
using i64 = long long;
using ld = double;
const int N = 5E3 + 5, Q = 1E7 + 5, MOD = INT_MAX;
const ld eps = 1E-6;
int n, q, posi[N], pposi[N];
i64 g[Q << 2], ra, rb;
struct pos {
  i64 x, y;
  bool operator < (const pos &w) const {
    return x == w.x ? y < w.y : x < w.x;
  }
} a[N];
struct que {
  i64 a; i64 b;
  bool operator < (const que &w) const {
    return a < w.a;
  }
} b[Q];
struct node {
  i64 X, Y; 
  int x;
  bool operator < (const node &w) const {
    i64 l = X * w.Y;
    i64 r = Y * w.X;
    if (l < r) return false;
    if (l > r) return true;
    return x > w.x;
  }
  node (i64 a, i64 b, int c) {X = a, Y = b, x = c;}
} ;
priority_queue <node> pq;
void push(int x) {
  if (x <= 1 || x >= n + 1) return ;
  if (a[x - 1] < a[x]) pq.emplace(node(a[x].y - a[x - 1].y, a[x].x - a[x - 1].x, x));
}
signed main(void) {
  ios :: sync_with_stdio(false);
  cin.tie(nullptr); cout.tie(nullptr);
  cin >> n;
  for (int i = 1; i <= n; ++i) cin >> a[i].x >> a[i].y;
  cin >> q >> g[0] >> ra >> rb;
  for (int i = 1; i <= 3 * q; ++i)
    g[i] = g[i - 1] * 48271 % MOD;
  for (int i = 1; i <= q; ++i) {
    b[i].a = -ra + g[3 * i - 2] % (2 * ra + 1);
    b[i].b = -rb + (g[3 * i - 1] * MOD % (2 * rb + 1) + g[3 * i]) % (2 * rb + 1);
  }
  sort(b + 1, b + 1 + q); sort(a + 1, a + 1 + n);
  for (int i = 2; i <= n; ++i) push(i);
  i64 sum = 0;
  for (int i = 1; i <= q; ++i) {
    int A = b[i].a;
    while (!pq.empty()) {
      i64 X = pq.top().X, Y = pq.top().Y; int x = pq.top().x;
      if (X != a[x].y - a[x - 1].y || Y != a[x].x - a[x - 1].x) {pq.pop(); continue;}
      i64 l = X, r = 1LL * Y * A;
      if (l >= r) break;
      pq.pop(); swap(a[x - 1], a[x]); 
      push(x - 1); push(x + 1); 
    }
    int l = 1, r = n + 1;
    while (l < r) {
      int mid = (l + r) >> 1;
      auto check = [&](int k) {
        return a[k].y >= 1LL * a[k].x * A + b[i].b;
      } ;
      if (check(mid)) r = mid;
      else l = mid + 1;
    }
    sum += n - l + 1;
  }
  cout << sum << '\n';
}

作者:CTHOOH

出处:https://www.cnblogs.com/CTHOOH/p/18064170

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   CTHOOH  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示