AT_abc424_f [ABC424F] Adding Chords - 洛谷 (luogu.com.cn)
又做 F 题,
依旧转化线段树,
心中生感慨。
没有原创内容所以是记录,这个老师写得特别好:
题解:AT_abc424_f [ABC424F] Adding Chords - 洛谷专栏 (luogu.com.cn)
简单说几句:
弦转化区间线段就不多说了。
建两个线段树,一个左端点对应区间维护右端点最大值,一个右端点对应区间维护左端点最大值。
设当前弦(区间)为 [x, y]。
在左端点区间线段树 [x + 1, y - 1] 中找最大的右端点 mx,在右端点区间线段树 [x + 1, y - 1] 中找最小的左端点 mn。
如果 mn < x || mx > y,就不能加 [x, y]。
否则加进线段树里。
如果 x + 1 > y - 1,说明两点是相邻点,可以随便加。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
const int INF = 0x3f3f3f3f;
int n, m;
#define lc(p) (p << 1)
#define rc(p) ((p << 1) | 1)
// 最大值线段树(记录右端点)
struct MaxSeg {
struct nod {
int l, r;
int mx; // 区间最大值
} t[N << 2];
void pu(int p) {
t[p].mx = max(t[lc(p)].mx, t[rc(p)].mx);
}
void bt(int p, int l, int r) {
t[p] = {l, r, 0};
if (l == r) return;
int md = (l + r) >> 1;
bt(lc(p), l, md);
bt(rc(p), md + 1, r);
}
void upd(int p, int x, int v) {
if (t[p].l == t[p].r) {
t[p].mx = v;
return;
}
int md = (t[p].l + t[p].r) >> 1;
if (x <= md) upd(lc(p), x, v);
else upd(rc(p), x, v);
pu(p);
}
int qry(int p, int L, int R) {
if (L > R) return 0;
if (L <= t[p].l && t[p].r <= R) {
return t[p].mx;
}
int md = (t[p].l + t[p].r) >> 1, res = 0;
if (L <= md) res = max(res, qry(lc(p), L, R));
if (R > md) res = max(res, qry(rc(p), L, R));
return res;
}
} max_seg; // 维护右端点最大值
// 最小值线段树(记录左端点)
struct MinSeg {
struct nod {
int l, r;
int mn; // 区间最小值
} t[N << 2];
void pu(int p) {
t[p].mn = min(t[lc(p)].mn, t[rc(p)].mn);
}
void bt(int p, int l, int r) {
t[p] = {l, r, INF};
if (l == r) return;
int md = (l + r) >> 1;
bt(lc(p), l, md);
bt(rc(p), md + 1, r);
}
void upd(int p, int x, int v) {
if (t[p].l == t[p].r) {
t[p].mn = v;
return;
}
int md = (t[p].l + t[p].r) >> 1;
if (x <= md) upd(lc(p), x, v);
else upd(rc(p), x, v);
pu(p);
}
int qry(int p, int L, int R) {
if (L > R) return INF;
if (L <= t[p].l && t[p].r <= R) {
return t[p].mn;
}
int md = (t[p].l + t[p].r) >> 1, res = INF;
if (L <= md) res = min(res, qry(lc(p), L, R));
if (R > md) res = min(res, qry(rc(p), L, R));
return res;
}
} min_seg; // 维护左端点最小值
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
// 初始化两棵线段树
max_seg.bt(1, 1, n);
min_seg.bt(1, 1, n);
while (m--) {
int x, y;
cin >> x >> y;
if (x > y) swap(x, y);
int L = x + 1, R = y - 1;
if (L <= R) {
int mn = min_seg.qry(1, L, R); // 查询左端点最小值
int mx = max_seg.qry(1, L, R); // 查询右端点最大值
if (mn < x || mx > y) {
cout << "No\n";
} else {
cout << "Yes\n";
// 更新:记录x对应y,y对应x
max_seg.upd(1, x, y);
min_seg.upd(1, y, x);
}
} else {
// 特殊情况:相邻点
cout << "Yes\n";
max_seg.upd(1, x, y);
min_seg.upd(1, y, x);
}
}
return 0;
}
4388

被折叠的 条评论
为什么被折叠?



