Closest Pair
[Link](Problem - F - Codeforces)
题意
给你 n n n个点每个点有一个权重 w i w_i wi,定义两个点的权重和为 a b s ( x i − x j ) × ( w i + w j ) abs (x_i-x_j)\times (w_i+w_j) abs(xi−xj)×(wi+wj),给你 m m m个询问,每次询问 [ l , r ] [l,r] [l,r]表示第 l l l到第 r r r个点里的最小点对权重和是多少。
思路
首先有性质1:对于两个点如果他们中间有个比他们两个最大值要小的点这两个点就不会构成最小点对,因为新的点和权值较小的点会构成一个 w w w和更小且 d x dx dx更小的权值和。
从前往后看每个点可以和他前面哪些点可能构成最小点对,对于一个点 x i x_i xi他只会和它前面比他 w w w大和第一个比他 w w w小的值构成最小点对,因为权值再小的点会和离他近的权值比 w i w_i wi小的点构成即不满足性质1,并且和 x i x_i xi构成的点不会和后面加进来的点构成最小点最,因为不如和 x i x_i xi构成的更小即不满足性质1。因此这样的点对最多有 O ( n ) O(n) O(n)个,我们设 p o s [ i ] pos[i] pos[i]为以 i i i结尾的和前面哪些点构成最小点对。
对于询问我们也设成 q [ i ] q[i] q[i]询问区间 r r r为 i i i的询问,然后对于某一个询问 [ l , r ] [l,r] [l,r]我们要找的是到 [ l , r ] [l,r] [l,r]里的最小点 ,对于前面的点对如果 [ l i , r i ] [l_i,r_i] [li,ri]想要可以被算贡献一定有 l i ≥ l l_i\ge l li≥l,也就是对于每一个 l i l_i li他只会被小于他的 l l l算到贡献即它贡献的区间为 [ 1 , l i ] [1,l_i] [1,li],这里我们可以用树状数组来维护前缀最小值,但是树状数组可以维护的 [ l , n ] [l,n] [l,n],所以我们可以转换一下每个 l i l_i li维护 [ n + 1 − l i , n ] [n+1-l_i,n] [n+1−li,n]的最小值,是等价的,然后查询 [ n + 1 − l i , n ] [n+1-l_i,n] [n+1−li,n]就可以了。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 3e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1);
const LL inf = 8e18;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m, k;
LL tr[N];
LL x[N], w[N];
vector<pair<int, LL>> pos[N];
int lowbit(int x) {
return x & -x;
}
void g(int a, int b) {
pos[a].push_back({b, (x[a] - x[b]) * (w[a] + w[b])});
}
void add(int x, LL v) {
for (; x <= n; x += lowbit(x)) tr[x] = min(tr[x], v);
}
LL query(int x) {
LL s = inf;
for (int i = x; i; i -= lowbit(i)) s = min(s, tr[i]);
return s;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> m;
stack<int> stk;
for (int i = 1; i <= n; i ++) {
cin >> x[i] >> w[i];
while (stk.size() && w[i] <= w[stk.top()]) {
g(i, stk.top());
stk.pop();
}
if (stk.size()) g(i, stk.top());
stk.push(i);
}
vector<PII> q[n + 1];
for (int i = 0; i < m; i ++) {
int l, r; cin >> l >> r;
q[r].push_back({l, i});
}
for (int i = 1; i <= n; i ++) tr[i] = inf;
vector<LL> res(m);
for (int i = 1; i <= n; i ++) {
for (auto t : pos[i]) add(n + 1 - t.x, t.y);
for (auto t : q[i]) res[t.y] = query(n + 1 - t.x);
}
for (int i = 0; i < m; i ++)
cout << res[i] << endl;
return 0;
}