题解:CF2096F Wonderful Impostors
zhang_kevin · · 题解
考虑维护一个数组
为了能够双指针预处理
令
这样,如果存在一个区间
考虑判断是否合法的 check() 函数,发现为了实现 check(),我们需要维护所有位置 check() 函数可以先判断
维护节点管辖区间内的
接下来为了维护
下面考虑插入或删除全
对于插入或删除至少有一个 multiset 即可实现。
综上,总时间复杂度为
:::info[参考代码]{open}
提交记录:https://codeforces.com/contest/2096/submission/398101702。
#include<bits/stdc++.h>
#define fo(i, l, r) for(int i = (l); i <= (r); ++i)
using namespace std;
const int N = 200005, inf = 1e9;
int T, n, m, q, x[N], a[N], b[N], ll[N];
multiset<int> s[N];
struct SegT{
int mn, minR, pre, preR, suf, sufR, tag;
bool flag;
}t[N << 2];
inline void push_up(int p, int l, int r){
int mid = (l + r) >> 1;
t[p].mn = min(t[p << 1].mn, t[p << 1 | 1].mn);
t[p].minR = min(t[p << 1].minR, t[p << 1 | 1].minR);
if(t[p << 1].mn == t[p].mn){
t[p].pre = t[p << 1].pre;
t[p].preR = t[p << 1].preR;
}else{
t[p].pre = max(t[p << 1 | 1].pre, mid);
t[p].preR = min(t[p << 1].minR, t[p << 1 | 1].preR);
}
if(t[p << 1 | 1].mn == t[p].mn){
t[p].suf = t[p << 1 | 1].suf;
t[p].sufR = t[p << 1 | 1].sufR;
}else{
t[p].suf = min(t[p << 1].suf, mid + 1);
t[p].sufR = min(t[p << 1 | 1].minR, t[p << 1].sufR);
}
int lsuf, lsufR, lflag, rpre, rpreR, rflag;
if(t[p << 1].mn > t[p].mn){
lsuf = l;
lsufR = t[p << 1].minR;
lflag = (t[p << 1].minR <= mid);
}else{
lsuf = t[p << 1].suf;
lsufR = t[p << 1].sufR;
lflag = t[p << 1].flag;
}
if(t[p << 1 | 1].mn > t[p].mn){
rpre = r;
rpreR = t[p << 1 | 1].minR;
rflag = (t[p << 1 | 1].minR <= r);
}else{
rpre = t[p << 1 | 1].pre;
rpreR = t[p << 1 | 1].preR;
rflag = t[p << 1 | 1].flag;
}
t[p].flag = lflag | rflag;
if(lsuf <= mid && rpre >= mid + 1 && min(lsufR, rpreR) <= rpre){
t[p].flag = true;
}
return;
}
inline void apply(int p, int k){
t[p].mn += k, t[p].tag += k;
return;
}
inline void push_down(int p){
if(!t[p].tag) return;
apply(p << 1, t[p].tag), apply(p << 1 | 1, t[p].tag);
t[p].tag = 0;
return;
}
inline void build(int p, int l, int r){
t[p].mn = t[p].tag = t[p].flag = 0;
if(l == r){
t[p].minR = t[p].preR = t[p].sufR = inf;
t[p].pre = -inf, t[p].suf = inf;
s[l].clear();
return;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid), build(p << 1 | 1, mid + 1, r);
push_up(p, l, r);
return;
}
inline void modify1(int p, int l, int r, int ql, int qr, int k){
if(r < ql || qr < l) return;
if(ql <= l && r <= qr) return apply(p, k), void();
int mid = (l + r) >> 1;
push_down(p);
modify1(p << 1, l, mid, ql, qr, k), modify1(p << 1 | 1, mid + 1, r, ql, qr, k);
push_up(p, l, r);
return;
}
inline void modify2(int p, int l, int r, int x, int k, int o){
if(x < l || x > r) return;
if(l == r){
if(o == 1){
s[x].insert(k);
t[p].minR = *s[x].begin();
}else{
s[x].erase(s[x].find(k));
if(s[x].empty()){
t[p].minR = inf;
}else t[p].minR = *s[x].begin();
}
return;
}
int mid = (l + r) >> 1;
push_down(p);
modify2(p << 1, l, mid, x, k, o), modify2(p << 1 | 1, mid + 1, r, x, k, o);
push_up(p, l, r);
return;
}
inline void insert(int x, int a, int b){
if(!x){
modify1(1, 1, n, a, b, 1);
return;
}
modify2(1, 1, n, a, b, 1);
return;
}
inline void erase(int x, int a, int b){
if(!x){
modify1(1, 1, n, a, b, -1);
return;
}
modify2(1, 1, n, a, b, -1);
return;
}
inline bool check(){
if(t[1].minR == inf) return true;
if(t[1].mn > 0) return false;
return !t[1].flag;
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> T; while(T--){
cin >> n >> m;
ll[0] = 1;
build(1, 1, n);
fo(i, 1, m){
cin >> x[i] >> a[i] >> b[i];
insert(x[i], a[i], b[i]);
ll[i] = ll[i - 1];
while(ll[i] < i && !check()){
erase(x[ll[i]], a[ll[i]], b[ll[i]]);
ll[i]++;
}
}
cin >> q; while(q--){
int l, r; cin >> l >> r;
cout << (l >= ll[r] ? "Yes" : "No") << '\n';
}
}
return 0;
}
:::