小白abc找典日记1:圆上画线

1.题目及链接

  • 题目链接:abc424-f
  • 题目预览:在一个顺时针编号为1,2,...,N的圆上有N个等距点.
    给出Q个询问并按顺序执行:给出 AᵢBᵢ 画出链接这两个点的线段,如果与先前存在的的线段相交则不画
    对于每个查询,询问这条线是否被画出(输出YesNo
  • 约束:
    • 2≤N≤10⁶
    • 1≤Q≤3×10⁵
    • 1≤Aᵢ<Bᵢ≤N
    • 所有输入均为整数
    • Aᵢ Bᵢ 两两不同

2.思路

  • 看到环优先考虑拆环,先从1号点拆开试一下,发现如果一条线(Aᵢ , Bᵢ)不能被画出,那么它必然被至少一根线"截断",即与之前存在的至少一根线相交且不包含
    转化成数学语言就是若对于询问 i,存在一个被画出的 j < i ,有
Aᵢ < Aⱼ < Bᵢ < Bⱼ
Aⱼ < Aᵢ < Bⱼ < Bᵢ
  • 好了,后面的事情就简单了,考虑维护两棵线段树,一棵记录右端点最大值,一棵记录左端点最小值即可

3.实现

每次搓线段树都觉得好麻烦
调了半天线段树发现特判写错了

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define lc p<<1 //左子
#define rc (p<<1)+1//右子
struct node {
	int l, r, num;
};
node t1[4000001];//右端点最大
node t2[4000001];//左端点最小
int inf = 1000000001;
void pushup1(int p) {
	t1[p].num = max(t1[lc].num, t1[rc].num);
}
void pushup2(int p) {
	t2[p].num = min(t2[lc].num, t2[rc].num);
}

void build1(int p,int ll,int rr) {
	t1[p] = { ll,rr,0 };
	if (ll == rr)return;
	int mid = (ll + rr) / 2;
	build1(lc, ll, mid); build1(rc, mid + 1, rr);
	pushup1(p);
}
void build2(int p, int ll, int rr) {
	t2[p] = { ll,rr,inf };
	if (ll == rr)return;
	int mid = (ll + rr) / 2;
	build2(lc, ll, mid); build2(rc, mid + 1, rr);
	pushup2(p);
}

void update1(int p, int pos, int k) {
	int x = t1[p].l; int y = t1[p].r;
	if (x==y) {
		t1[p].num = max(t1[p].num, k);
		return;
	}
	int mid = (x + y) / 2;
	if (pos <= mid)update1(lc, pos, k);
	else update1(rc, pos, k);
	pushup1(p);
}
void update2(int p, int pos, int k) {
	int x = t2[p].l; int y = t2[p].r;
	if (x==y) {
		t2[p].num = min(t2[p].num, k);
		return;
	}
	int mid = (x + y) / 2;
	if (pos <= mid)update2(lc, pos, k);
	else update2(rc, pos, k);
	pushup2(p);
}
int q1(int p,int ll, int rr) {
	int x = t1[p].l; int y = t1[p].r;
	if (x >= ll && y <= rr)return t1[p].num;
	int res = 0;
	int mid = (x + y) / 2;
	if (ll <= mid)res = max(res, q1(lc, ll, rr));
	if (rr > mid)res = max(res, q1(rc, ll, rr));
	return res;
}
int q2(int p, int ll, int rr) {
	int x = t2[p].l; int y = t2[p].r;
	if (x >= ll && y <= rr)return t2[p].num;
	int res = inf;
	int mid = (x + y) / 2;
	if (ll <= mid)res = min(res, q2(lc, ll, rr));
	if (rr > mid)res = min(res, q2(rc, ll, rr));
	return res;
}
int main() {
	int n, q;
	cin >> n >> q;
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	build1(1, 1, n); build2(1, 1, n);
	for (int i = 1; i <= q; i++) {
		int a, b;
		cin >> a >> b;
		if (a+1>b-1) {
			cout << "Yes" << endl;
			update1(1, a, b);
			update2(1, b, a);
			continue;
		}
		int left = q2(1, a + 1, b - 1);
		int right = q1(1, a + 1, b - 1);
		if (left< a || right > b) {
			cout << "No" << endl;
		}
		else {
			cout << "Yes" << endl;
			update1(1, a, b);
			update2(1, b, a);
		}
	}
	return 0;
}
posted @ 2025-12-05 19:28  匚块wxw  阅读(0)  评论(2)    收藏  举报