小白abc找典日记1:圆上画线
1.题目及链接
- 题目链接:abc424-f
- 题目预览:在一个顺时针编号为1,2,...,N的圆上有N个等距点.
给出Q个询问并按顺序执行:给出 Aᵢ 和 Bᵢ 画出链接这两个点的线段,如果与先前存在的的线段相交则不画
对于每个查询,询问这条线是否被画出(输出Yes或No) - 约束:
- 2≤N≤10⁶
- 1≤Q≤3×10⁵
- 1≤Aᵢ<Bᵢ≤N
- 所有输入均为整数
- Aᵢ Bᵢ 两两不同
2.思路
- 看到环优先考虑拆环,先从1号点拆开试一下,发现如果一条线(Aᵢ , Bᵢ)不能被画出,那么它必然被至少一根线"截断",即与之前存在的至少一根线相交且不包含
转化成数学语言就是若对于询问 i,存在一个被画出的 j < i ,有
- 好了,后面的事情就简单了,考虑维护两棵线段树,一棵记录右端点最大值,一棵记录左端点最小值即可
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;
}

浙公网安备 33010602011771号