CF1635F. Closest Pair (2800) (贪心,离线,树状数组)
https://codeforces.com/contest/1635/problem/F
题意
给出3e5个点,每个点有一个权值\(wi\), 定义两个点的权值为\(|(x_{i} - x_{j}) * (w_{i} + w_{j})|\),有3e5个询问,每次询问\([l, r]\)区间中两点的最小权值,(xi和wi都是递增给出的)
思路
- 性质: 若两个点i,j要成为Closest Pair,则他们中间不能有小于 max(wi, wj) 的点,否则中间这个点和 min(wi, wj) 可以形成更优的答案。
- 对于一个点xi,他只会和前面离他较近且比他大的①或者第一个比他小的②组成CP。和xi配对的点不会和后面加进来的组,因为wi是递增给出的,这不满足上面性质
- 我们用单调栈找出所有对,计算一对的权值按xi离线,把询问按r离线。
- 我们用树状数组找区间最小值时候需要l到r (等价l到n)的最小值,需要后缀最值,但是树状数组只能维护前缀最值,所以把下标取负+n+1,正常操作就是后缀最值了。
#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2);
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
const double PI = acos(-1.0);
typedef long long ll;
const int N = 5e5+ 5 ;//////
const int M = 1e5 + 5;
const double eps =1e-13;
const ll mod = 998244353;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3fll;
typedef pair<int,int> PII;
int n, m, a[N], b[N], pre[N], pos[N], ans[N];
struct chimer{
int l, id;
};
struct node{
int val;
}tree[N << 2];
vector<chimer> Q[N];
void push_up(int rt) {
tree[rt].val = min(tree[rt << 1].val, tree[rt << 1 | 1].val);
}
void build(int l, int r, int rt) {
if(l == r) {
tree[rt].val = 0x3f3f3f3f; return;
}
int mid = l + r >> 1;
build(l, mid, rt << 1); build(mid + 1, r, rt << 1 | 1);
push_up(rt);
}
int query(int a, int b, int l, int r, int rt) {
if(b < l || a > r) return INF;
if(l >= a && r <= b) {
return tree[rt].val;
}
int mid = l + r >> 1;
return min(query(a, b, l, mid, rt << 1), query(a, b, mid + 1, r, rt << 1 | 1));
}
void modify(int pos, int x, int l, int r, int rt) {
if(l == r) {
tree[rt].val = x;
return;
}
int mid = l + r >> 1;
if(pos <= mid) modify(pos, x, l, mid, rt << 1);
else modify(pos, x, mid + 1, r, rt << 1 | 1);
push_up(rt);
}
void de(int l, int r, int rt) {
if(l == r) {
cout << l << ":" << tree[rt].val << " "; return;
}
int mid = l + r >> 1;
de(l, mid, rt << 1); de(mid + 1, r, rt << 1 | 1);
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]), b[i] = a[i];
for(int i = 1; i <= m; ++ i) { int l, r; scanf("%d %d", &l, & r); Q[r].push_back({l, i});}
sort(b + 1, b + n + 1); int tot = unique(b + 1, b + n + 1) - b - 1;
for(int i = 1; i <= n; ++ i) {
int num = lower_bound(b + 1, b + tot + 1, a[i]) - b;
pos[i] = pre[num], pre[num] = i;
}
build(1, n, 1);
for(int i = 1; i <= n; ++ i) {
if(pos[i]) modify(pos[i], i - pos[i], 1, n, 1);
for(auto j : Q[i]) {
ans[j.id] = query(j.l, i, 1, n, 1);
}
}
//de(1, n, 1);
for(int i = 1; i <= m; ++ i) {
if(ans[i] == INF) ans[i] = -1;
printf("%d\n", ans[i]);
}
return 0;
}