ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【CF1635F】 Closest Pair 题解

2022-07-20 09:34:39  阅读:163  来源: 互联网

标签:Closest rep int 题解 top 区间 maxn Pair 节点


CF 传送门:CF1635F

找性质规律 + 单调栈 + 线段树

Solution

1

考场上想出了把那些点对扔进单调队列然后乱搞的做法。发现对于一个询问区间,如果想要直接都扔进单调队列然后从中找到带权距离最小值复杂度仍然很高。

换句话说,我们无法直接得到区间最优解。那不妨来试着求解单点最优解,然后在询问区间内合并答案得到最优。

2

一般这种情况,需要我们讨论 3 个或以上个节点寻找性质规律。先考虑全局。

不妨假设有三个节点 \(a,\ b,\ c\),满足 \(x_a<x_b<x_c\) 且 \(w_b<w_c\)。不考虑 \(w_a\) 的数量关系是因为若这个性质需要 \(w\) 也满足单调(\(x\) 本身满足单调),那么限制条件过多,不好做。

我们由此可以发现,三点不论怎样组合,\(d(a,c)\) 一定不是最优的——\(d(a,b),\ d(b,c)\) 显然都比他优。又因为我们要寻找单点最优解,故对于节点 \(c\) 而言,节点 \(b\) 之前的节点对它都没有意义(换句话说,对全局不会有贡献)。 这个性质对 \(c<b<a\) 的情况同样成立。

综述,对于每个节点 \(i\),我们都可以找到两个相应节点 \(l_i,\ r_i\),满足 \(l_i<i,\ W_{l_i}<W_i,\ r_i>i,\ W_{r_i}<W_i\)。而有且仅有这 \(2n\) 个点对可以对全局结果产生贡献(因为它们相对其他点对都更优)。

3

回过头看区间上如何处理。

自然会有疑问:对于一个单点 \(i\),如果其 \(l_i\) 与 \(r_i\) 都在区间询问范围之外,即我们考虑不到,但是 \(i\) 本身却可以和区间内其他节点构成本区间的最优解呢?

为了解决这个问题,不妨构造出一个和问题所述一样的情景:对于询问区间 \([L,R]\),有带权距离最小的点对 \((a,b)|w_a<w_b\),满足 \(a>l_b\)。

按照上面得到的性质,如果 \(w_a<w_b\) 且 \(a<b\),那么显然 \(l_b=a\),与假设矛盾。而 \(w_b>w_a\) 的情况同理。

综上,我们得到结论:区间内的带权距离最小的点对一定属于那 \(2n\) 个点对之中。

4

\(l_i\) 和 \(r_i\) 可以通过单点栈得到。

直觉经验告诉我们查找区间最优点对可以使用线段树实现。具体地,将每个 \(d(l_i,i)\) 存在点 \(l_i\) 上,\(r_i\) 同理,再将询问离线下来,按 \(R\) 升序依次查询处理即可。

Code

#include<bits/stdc++.h>
using namespace std;
 
#define int long long
#define per(i, a, b) for(register int i = a; i >= b; --i)
#define rep(i, a, b) for(register int i = a; i <= b; ++i)
const int maxn = 3e5 + 5;
int n, q;
int x[maxn], w[maxn], st[maxn], top;
struct node{int l, id;};
vector<node> que[maxn];
int ans[maxn];
vector<int> p[maxn];
int fr[maxn], bc[maxn], l, r;
 
struct segment_tree{
    #define ls(x) (x<<1)
    #define rs(x) (x<<1|1)
    int mn[maxn << 2];
    inline void updt(int i, int l, int r, int pos, int k){
        if(l == r){
            mn[i] = min(mn[i], k); return;
        }
        int mid = l + r >> 1;
        if(pos <= mid) updt(ls(i), l, mid, pos, k); else updt(rs(i), mid + 1, r, pos, k);
        mn[i] = min(mn[ls(i)], mn[rs(i)]);
    }
    inline int qry(int i, int l, int r, int L, int R){
        if(l >= L and r <= R) return mn[i];
        int mid = l + r >> 1, res = 5e18;
        if(L <= mid) res = min(res, qry(ls(i), l, mid, L, R));
        if(R > mid) res = min(res, qry(rs(i), mid + 1, r, L, R));
        return res;
    }
}T;
 
signed main(){
    scanf("%lld%lld", &n, &q);
    rep(i, 1, n << 2) T.mn[i] = 5e18;
    rep(i, 1, n) scanf("%lld%lld", &x[i], &w[i]);
    rep(i, 1, n){
        while(top and w[st[top]] > w[i]) top -= 1;
        fr[i] = st[top], st[++top] = i;
    } top = 0;
    per(i, n, 1){
        while(top and w[st[top]] > w[i]) top -= 1;
        bc[i] = st[top], st[++top] = i;
    }
    rep(i, 1, n){
        if(fr[i]) p[i].push_back(fr[i]);
        if(bc[i]) p[bc[i]].push_back(i); 
    }
    rep(i, 1, q) 
        scanf("%lld%lld", &l, &r), ans[i] = 5e18, que[r].push_back({l, i});
    rep(i, 1, n){
        for(auto j : p[i]) T.updt(1, 1, n, j, 1ll * abs(x[i] - x[j]) * (w[i] + w[j]));
        for(auto j : que[i]) ans[j.id] = T.qry(1, 1, n, j.l, i);
    }
    rep(i, 1, q) printf("%lld\n", ans[i]);
    return 0;
}

标签:Closest,rep,int,题解,top,区间,maxn,Pair,节点
来源: https://www.cnblogs.com/gsn531/p/16496619.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有