题解 P9062【[Ynoi2002] Adaptive Hsearch&Lsearch】
题意
有 $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~

浙公网安备 33010602011771号