题解 P9062【[Ynoi2002] Adaptive Hsearch&Lsearch】

$\text{Link}$

题意

有 $n$ 个平面上的点 $(x_i,y_i)$,$q$ 次询问,每次询问给出 $l,r$,求 $\displaystyle\min_{l\le i<j\le r}\text{dis}(i,j)$。

$n,q\le 2.5\times 10^5$,时限 6s。

思路

令 $v=\max(x_i,y_i)$。

依照区间最近点对的通用思路,我们考虑找有效点对。这题里确定有效的点对很难确切找到,我们只能保证找到所有的有效点对并且总点对数合理。

我们定一个底数 $d$,枚举 $0\le k\le \log_dv$,我们把平面划分为若干个 $d^k\times d^k$ 的正方形块中。

我们对每个块维护块内的所有点,枚举每个点 $i$,我们考虑将以其所在的块为中心的 $3\times 3$ 的块内的所有点和 $i$ 都放入点对中,再将 $i$ 放入该块中。很显然这样复杂度会爆炸,于是我们加一个限制,在加入点 $i$ 时,删掉 $3\times 3$ 块内所有与 $i$ 距离小于 $d^{k-1}$ 的点。

考虑正确性:设 $p<q<r$,如果 $(p,r)$ 是有贡献的点对,但是 $\text{dis}(p,q)<d^{k-1}$,显然 $\text{dis}(p,r)<\text{dis}(p,q)<d^{k-1}$,我们将 $k$ 减小来讨论,必然会出现一个时候 $d^{k-1}\le\text{dis}(p,q)<d^{k}$,这时 $p$ 不会被 $q$ 删除,因为 $\text{dis}(p,r)<\text{dis}(p,q)<d^{k}$,所以 $p,r$ 在相邻块中,必然会被计入。如果另有 $p<s<r$ 有 $\text{dis}(p,s)<d^{k-1}$ 可以继续减小 $k$ 讨论。

考虑复杂度:在一个块中,点数最多是 $O(d^4)$ 带小常数级别的(?),如果令 $d$ 为常数,则一个点会对点对总数造成 $O(\log v)$ 的贡献。

点对总数虽然是 $O(n\log v)$ 级别,但是常数实在太大,我们在扫描线时用树状数组都会很慢,最好使用 $O(1)-O(\sqrt n)$ 的分块。

块内的点用手写哈希表存 vector,不要用 umap 之类的玩意。(更不能用 map,理论复杂度会退化)

时间复杂度 $O(n\log v+q\sqrt n)$,取 $d=4$ 跑得最快。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
#define vec vector<int>
const int N=2.5e5+10,sq=512,B=1e9+10;
const ll INF=1e18;
int n,q,px[N],py[N];
ll ans[N];
vector<int>use[N];
struct Query{
    int l,id;
};
vector<Query>qr[N];
inline void push(int u,int v){
    if(u>v) swap(u,v);
    use[v].emplace_back(u);
//  printf("use %d %d\n",u,v);
}
inline ll sqr(int x){
    return 1ll*x*x;
}
inline ll dis(int x,int y){
    return sqr(px[x]-px[y])+sqr(py[x]-py[y]);
}
struct SQR{
    ll mn1[N],mn2[N];
    int bel[N],br[N];
    inline void init(){
        for(int i=1,k=1;i<=n;i+=sq,k++){
            for(int j=i;j<=min(i+sq-1,n);j++)
                bel[j]=k,mn1[j]=mn2[j]=INF;
            br[k]=min(i+sq-1,n);
        }
    }
    inline void add(int p,ll v){
        mn1[p]=min(mn1[p],v);
        mn2[bel[p]]=min(mn2[bel[p]],v);
    }
    inline ll query(int p){
        ll ans=INF;
        for(int i=p;i<=br[bel[p]];i++)
            ans=min(ans,mn1[i]);
        for(int i=bel[p]+1;i<=bel[n];i++)
            ans=min(ans,mn2[i]);
        return ans;
    }
}T;
template<class P,class Q>
class HashTable{
    static const int mod=5e5+9,L=mod+10;
    int head[L],nxt[N],siz;
    P val[N];
    Q sav[N];
    public:
    inline void clear() {
        for(int i=1;i<=siz;i++){
            head[val[i]%mod]=0,nxt[i]=val[i]=0;
            Q tmp;
            swap(sav[i],tmp);
        }
        siz=0;
    }
    inline void insert(P y){
        val[++siz]=y;
        nxt[siz]=head[y%mod];
        head[y%mod]=siz;
    }
    inline Q &operator[](const P y) {
        int x=y%mod;
        for(int i=head[x];i;i=nxt[i])
            if(val[i]==y)
                return sav[i];
        insert(y);
        return sav[siz];
    }
    inline bool count(const P y) {
        int x=y%mod;
        for(int i=head[x];i;i=nxt[i])
            if(val[i]==y)
                return 1;
        return 0;
    }
};
HashTable<ll,vec>mp;
inline ll mpr(int a,int b){
    return 1ll*a*B+b;
}
int main(){
    n=read(),q=read();
    for(int i=1;i<=n;i++)
        px[i]=read(),py[i]=read(); 
    T.init();
    for(int i=1;i<=q;i++){
        int l=read(),r=read();
        qr[r].push_back({l,i});
    }
    for(int s=0;s<=28;s+=2){
        mp.clear();
        for(int i=1;i<=n;i++){
            int x=px[i],y=py[i];
            int bx=x>>s,by=y>>s;
            for(int dx=-1;dx<=1;dx++)
                for(int dy=-1;dy<=1;dy++){
                    if(bx+dx<0||by+dy<0) continue;
                    if(!mp.count(mpr(bx+dx,by+dy))) continue;
                    vec tmp,tmq=mp[mpr(bx+dx,by+dy)];
                    tmp.clear();
                    for(auto p:tmq){
                        push(p,i);
                        if(dis(p,i)>=(1ll<<(s*2-4))) tmp.push_back(p);
                    }
                    mp[mpr(bx+dx,by+dy)]=tmp;
                }
            mp[mpr(bx,by)].emplace_back(i);
        }
    }
    for(int i=1;i<=n;i++){
        sort(use[i].begin(),use[i].end());
        use[i].resize(unique(use[i].begin(),use[i].end())-use[i].begin());
//      for(auto j:use[i])
//          printf("use %d %d %lld\n",j,i,dis(i,j));
    }
    for(int i=1;i<=n;i++){
        for(auto t:use[i])
            T.add(t,dis(t,i));
        for(auto t:qr[i])
            ans[t.id]=T.query(t.l);
    }
    for(int i=1;i<=q;i++)
        write(ans[i]),putc('\n');
    flush();
}

再见 qwq~

posted @ 2023-02-13 07:15  ffffyc  阅读(14)  评论(0)    收藏  举报  来源