Description
给定 n n n 个点 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ⋯ , ( x n , y n ) (x_1,y_1),(x_2,y_2),\cdots,(x_n,y_n) (x1,y1),(x2,y2),⋯,(xn,yn),进行 m m m 次操作,有以下两种:
- U i x y \texttt{U} \; i\;x \;y Uixy:将第 i i i 个点修改为 ( x , y ) (x,y) (x,y)。
- Q l r \texttt{Q} \; l \; r Qlr:求 min i = 1 n { x i − y i } ( x i ∈ [ l , r ] , y i ∈ [ l , r ] ) \min_{i=1}^{n} \{x_i-y_i \} \quad (x_i\in[l,r],y_i\in[l,r]) mini=1n{xi−yi}(xi∈[l,r],yi∈[l,r]),若没有满足条件的点,答案为 0 0 0。
强制在线,每次操作的参数需要异或上一次的答案,如没有则不需要。
Limitations
1
≤
n
,
m
≤
5
×
1
0
5
1 \le n,m \le 5\times 10^5
1≤n,m≤5×105
1
≤
l
≤
r
≤
n
1 \le l \le r \le n
1≤l≤r≤n (实际)
1
≤
y
≤
x
≤
n
\textcolor{red}{1 \le y \le x \le n}
1≤y≤x≤n(实际)
2
s
,
512
MB
2\texttt{s},512\texttt{MB}
2s,512MB
Solution
注意到 y ≤ x y \le x y≤x,可以把问题转化为:给定 n n n 个区间,支持修改某个区间,查询包含于 [ l , r ] [l,r] [l,r] 的区间的长度的最小值。
由于能修改而且强制在线,我们不能直接数点。
但我们可以排除包含了其他区间的区间,显然它不可能成为答案。
此时左右端点均单调不降,只需要找出第一个 ≥ l \ge l ≥l 的 l p l_p lp 和最后一个 ≤ r \le r ≤r 的 r q r_q rq,答案就是 min i = p q { r i − l i } \min_{i=p}^q \{r_i-l_i\} mini=pq{ri−li}
实现上,无需删掉没用的区间,只需将区间按右端点分开维护,只管一个右端点对应的最大左端点即可,顺便解决了 q q q。
使用 multiset
和线段树维护,
p
p
p 可以在线段树上二分求得,时间复杂度
O
(
(
n
+
q
)
log
n
)
\mathcal{O}((n+q)\log n)
O((n+q)logn)。
Code
3.77 KB , 1.3 s , 80.71 MB (in total) 3.77\texttt{KB},1.3\texttt{s},80.71\texttt{MB} \; \text{(in total)} 3.77KB,1.3s,80.71MB(in total)
// Problem: P11210 『STA - R8』强制在线动态二维数点
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P11210
// Memory Limit: 512 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
int ls(int u) { return u * 2 + 1; }
int rs(int u) { return u * 2 + 2; }
struct Node {
int l, r, mx, mi;
};
const int inf = 1e9;
using Tree = vector<Node>;
void pushup(Tree &tr, int u) {
tr[u].mx = max(tr[ls(u)].mx, tr[rs(u)].mx);
tr[u].mi = min(tr[ls(u)].mi, tr[rs(u)].mi);
}
void build(Tree &tr, int u, int l, int r, vector<multiset<int>> &S) {
tr[u].l = l;
tr[u].r = r;
if (l == r) {
if (S[l].empty()) {
tr[u].mx = 0;
tr[u].mi = inf;
}
else {
tr[u].mx = *prev(S[l].end());
tr[u].mi = l - tr[u].mx;
}
return;
}
int mid = (l + r) >> 1;
build(tr, ls(u), l, mid, S);
build(tr, rs(u), mid + 1, r, S);
pushup(tr, u);
}
void modify(Tree &tr, int u, int p, vector<multiset<int>> &S) {
if (tr[u].l == tr[u].r) {
if (S[tr[u].l].empty()) {
tr[u].mx = 0;
tr[u].mi = inf;
}
else {
tr[u].mx = *prev(S[tr[u].l].end());
tr[u].mi = tr[u].l - tr[u].mx;
}
return;
}
int mid = (tr[u].l + tr[u].r) >> 1;
if (p <= mid) {
modify(tr, ls(u), p, S);
}
else {
modify(tr, rs(u), p, S);
}
pushup(tr, u);
}
int query(Tree &tr, int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) {
return tr[u].mi;
}
int mid = (tr[u].l + tr[u].r) >> 1;
int res = inf;
if (l <= mid) {
res = min(res, query(tr, ls(u), l, r));
}
if (r > mid) {
res = min(res, query(tr, rs(u), l, r));
}
return res;
}
int find_first(Tree &tr, int u, int l, int r, int v) {
if (tr[u].r < l || tr[u].l > r || tr[u].mx < v) {
return -1;
}
if (tr[u].l == tr[u].r) {
return tr[u].l;
}
int res = find_first(tr, ls(u), l, r, v);
if (res == -1) {
res = find_first(tr, rs(u), l, r, v);
}
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, q;
cin >> n >> q;
vector<multiset<int>> S(n);
vector<int> x(n), y(n);
for (int i = 0; i < n; i++) {
cin >> x[i] >> y[i];
x[i]--, y[i]--;
S[x[i]].insert(y[i]);
}
Tree tr(n << 2);
build(tr, 0, 0, n - 1, S);
auto update = [&](int i, int a, int b) {
S[x[i]].extract(y[i]);
modify(tr, 0, x[i], S);
x[i] = a;
y[i] = b;
S[x[i]].insert(y[i]);
modify(tr, 0, x[i], S);
};
auto get = [&](int l, int r) {
int fir = find_first(tr, 0, l, r, l);
if (fir == -1) {
return 0;
}
return query(tr, 0, fir, r);
};
int ans = 0;
for (int i = 0; i < q; i++) {
char op;
cin >> op;
if (op == 'U') {
int i, a, b;
cin >> i >> a >> b;
i ^= ans, a ^= ans, b ^= ans;
i--, a--, b--;
update(i, a, b);
}
else {
int l, r;
cin >> l >> r;
l ^= ans, r ^= ans;
l--, r--;
cout << (ans = get(l, r)) << endl;
}
}
return 0;
}