社区讨论

82pts 求卡常

P3122 [USACO15FEB] Fencing the Herd G参与者 2已保存回复 6

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
6 条
当前快照
1 份
快照标识符
@mhjug80l
此快照首次捕获于
2025/11/04 08:41
4 个月前
此快照最后确认于
2025/11/04 08:41
4 个月前
查看原帖
[最新的一个评测记录]。(https://www.luogu.com.cn/record/213387761)
目前 82pts T 3 个点。
思路是直接用非旋 Treap 动态维护上下凸包。
由于为了卡常写了一堆乱七八糟的代码,我会加注释的。
CPP
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int inf = 0x3f3f3f3f;
#define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
struct IO {
#define MAXSIZE (1 << 20)
#define isdigit(x) (x >= '0' && x <= '9')
  char buf[MAXSIZE], *p1, *p2;
  char pbuf[MAXSIZE], *pp;
#if DEBUG
#else
  IO() : p1(buf), p2(buf), pp(pbuf) {}

  ~IO() { fwrite(pbuf, 1, pp - pbuf, stdout); }
#endif
  char gc() {
#if DEBUG  // 调试,可显示字符
    return getchar();
#endif
    if (p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin);
    return p1 == p2 ? ' ' : *p1++;
  }

  bool blank(char ch) {
    return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
  }

  template <class T>
  T read(T &x) {
    double tmp = 1;
    bool sign = 0;
    x = 0;
    char ch = gc();
    for (; !isdigit(ch); ch = gc())
      if (ch == '-') sign = 1;
    for (; isdigit(ch); ch = gc()) x = x * 10 + (ch - '0');
    if (ch == '.')
      for (ch = gc(); isdigit(ch); ch = gc())
        tmp /= 10.0, x += tmp * (ch - '0');
    if (sign) x = -x;
		return x;
  }

  void read(char *s) {
    char ch = gc();
    for (; blank(ch); ch = gc());
    for (; !blank(ch); ch = gc()) *s++ = ch;
    *s = 0;
  }

  void read(char &c) { for (c = gc(); blank(c); c = gc()); }

  void push(const char &c) {
#if DEBUG  // 调试,可显示字符
    putchar(c);
#else
    if (pp - pbuf == MAXSIZE) fwrite(pbuf, 1, MAXSIZE, stdout), pp = pbuf;
    *pp++ = c;
#endif
  }

  template <class T>
  void write(T x) {
    if (x < 0) x = -x, push('-');  // 负数输出
    static T sta[35];
    T top = 0;
    do {
      sta[top++] = x % 10, x /= 10;
    } while (x);
    while (top) push(sta[--top] + '0');
  }

  template <class T>
  void write(T x, char lastChar) {
    write(x), push(lastChar);
  }
} io;
int n, m, rt[2], idx[2], maxx = -2147483648, minx = 2147483647;
ll c;
struct node {
	int ls, rs, sz, x, y, pr;
}tr[2][400001];//平衡树(凸包),按照 x 排序 tr[0]是上凸包 tr[1]是下凸包 
inline void split(int op, int x, int k, int &lrt, int &rrt) { 
	if (! x) return lrt = rrt = 0, void();
	if (tr[op][x].x <= k) lrt = x, split(op, tr[op][x].rs, k, tr[op][x].rs, rrt);
	else rrt = x, split(op, tr[op][x].ls, k, lrt, tr[op][x].ls);
	tr[op][x].sz = tr[op][tr[op][x].ls].sz + tr[op][tr[op][x].rs].sz + 1;
}
inline ll merge(int op, int lrt, int rrt) {
	if ((! lrt) || (! rrt)) return lrt | rrt;
	if (tr[op][lrt].pr >  tr[op][rrt].pr) return tr[op][lrt].rs = merge(op, tr[op][lrt].rs, rrt), tr[op][lrt].sz = tr[op][tr[op][lrt].ls].sz + tr[op][tr[op][lrt].rs].sz + 1, lrt;
	return tr[op][rrt].ls = merge(op, lrt, tr[op][rrt].ls), tr[op][rrt].sz = tr[op][tr[op][rrt].ls].sz + tr[op][tr[op][rrt].rs].sz + 1, rrt;
}
inline ll rkgetx(int op, int x, int rk) {//给定排名 rk 获得 x 第 rk 小的点 
	if (rk == tr[op][tr[op][x].ls].sz + 1) return x;
	if (rk <= tr[op][tr[op][x].ls].sz) return rkgetx(op, tr[op][x].ls, rk);
	return rkgetx(op, tr[op][x].rs, rk - tr[op][tr[op][x].ls].sz - 1);
}
inline void insert_tb(ll op, ll x, ll y) {//将点插入凸包 
	int lrt, rrt, trt;
	split(op, rt[op], x - 1, lrt, rrt);
	split(op, rrt, x, trt, rrt);
	if (trt && ((tr[op][trt].y > y && !op) || (tr[op][trt].y < y && op))) {//判断有无与自己 x 相同的点,留下更高/更低的点 
		merge(op, lrt, merge(op, trt, rrt));
		return ; 
	}	
	tr[op][++ idx[op]] = {0, 0, 1, x, y, rand() | (rand() << 16)};
	ll sx, sy;
	if (tr[op][lrt].sz && tr[op][rrt].sz) {
		int ls = rkgetx(op, lrt, tr[op][lrt].sz), rs = rkgetx(op, rrt, 1);
		sx = 1ll * (tr[op][idx[op]].x - tr[op][ls].x) * (tr[op][rs].y - tr[op][idx[op]].y), sy = 1ll * (tr[op][idx[op]].y - tr[op][ls].y) * (tr[op][rs].x - tr[op][idx[op]].x);
		if (ls && rs && ((sy <= sx && !op) || (op && sy >= sx))) {
			idx[op] --, merge(op, lrt, rrt);
			return ;
		} 
	}
	int l = 1, r = tr[op][lrt].sz - 1, ans = r + 1, mid, tm, tm1;// 二分这个点左边有哪些点会被删掉 
	while (l <= r) {
		mid = l + r >> 1, tm = rkgetx(op, lrt, mid), tm1 = rkgetx(op, lrt, mid + 1);
		sx = 1ll * (tr[op][tm1].x - tr[op][tm].x) * (tr[op][idx[op]].y - tr[op][tm1].y), sy = 1ll * (tr[op][tm1].y - tr[op][tm].y) * (tr[op][idx[op]].x - tr[op][tm1].x);
		//斜率我怕精度炸同时除法时间长就移项换成乘法了。a / b < c / d -> a * d < c * b (b,d>0) 
		if (op ^ (sy <= sx)) ans = mid, r = mid - 1;
		else l = mid + 1;
	}	 
	if (ans < tr[op][lrt].sz) trt = rkgetx(op, lrt, ans), split(op, lrt, tr[op][trt].x, lrt, trt);
	l = 2, r = tr[op][rrt].sz, ans = 1;// 二分这个点右边有哪些点会被删掉 
	while (l <= r) {
		mid = l + r >> 1, tm = rkgetx(op, rrt, mid), tm1 = rkgetx(op, rrt, mid - 1);
		sx = 1ll * (tr[op][tm].x - tr[op][tm1].x) * (tr[op][tm1].y - tr[op][idx[op]].y), sy = 1ll * (tr[op][tm].y - tr[op][tm1].y) * (tr[op][tm1].x - tr[op][idx[op]].x);
		if (op ^ (sx <= sy)) ans = mid, l = mid + 1;
		else r = mid - 1;
	}
	if (ans > 1) trt = rkgetx(op, rrt, ans), split(op, rrt, tr[op][trt].x - 1, trt, rrt);
	//删掉之后加点 
	rt[op] = merge(op, lrt, merge(op, idx[op], rrt));
}
inline ll fd(int op, int a, int b) {//找到最大/最小的ax+by。 
	int l = 1, r = tr[op][rt[op]].sz - 1, ans = r + 1, mid, tm, tm1;
	ll sx, sy;
	//找到斜率第一个大于/小于-a/b的点
	while (l <= r) {
		mid = l + r >> 1, tm = rkgetx(op, rt[op], mid), tm1 = rkgetx(op, rt[op], mid + 1);
		sx = -1ll * a * (tr[op][tm1].x - tr[op][tm].x), sy = 1ll * b * (tr[op][tm1].y - tr[op][tm].y);
		//同样移项过了。处理过了保证 b > 0。 
		if (op ^ (sy < sx)) ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	ans = rkgetx(op, rt[op], ans);
	return 1ll * tr[op][ans].x * a + 1ll * tr[op][ans].y * b;
} 
signed main() {
//	freopen ("P3122_10.in", "r", stdin);
//	freopen ("sb.out", "w", stdout);
//	system ("fc sb.out P3122_10.out");
	srand(114514);
	n = io.read(n), m = io.read(m);
	int x, y;
	while(n -- ) {
		x = io.read(x), y = io.read(y);
		insert_tb(0, x, y), insert_tb(1, x, y);//插入凸包 
		maxx = max(maxx, x), minx = min(minx, x);//当 b = 0 时方便处理 
	}
	int op, a, b;
	while (m -- ) {
		op = io.read(op), a = io.read(a), b = io.read(b);
		if (op & 1) {
			insert_tb(0, a, b), insert_tb(1, a, b);//插入凸包 
			maxx = max(maxx, a), minx = min(minx, a);//当 b = 0 时方便处理 
		}
		else {
			c = io.read(c);
			if (!b) {
				if (a < 0) a = -a, c = -c;//移项方便 
				if (1ll * maxx * a < c || 1ll * minx * a > c) putchar('Y'), putchar('E'), putchar('S'), putchar('\n');
				else putchar('N'), putchar('O'), putchar('\n');
			} 
			else {
				if (b < 0) a = -a, b = -b, c = -c;//移项方便
				if (fd(0, a, b) < c || fd(1, a, b) > c) putchar('Y'), putchar('E'), putchar('S'), putchar('\n');
				else putchar('N'), putchar('O'), putchar('\n');
			}
		}
		
	}
}

回复

6 条回复,欢迎继续交流。

正在加载回复...