题解 星空
- 遇到形如 \(| |x_1-x_2| \pm |y_1-y_2| |\) 的柿子,一定要注意是不是可以转化为切比雪夫距离求解!
考试的时候只想到 \(n^2\) 做法,先并查集维护距离为零的点,再枚举点对更新距离
这个做法的复杂度瓶颈在于枚举点对求最小距离的过程
发现题面里给的柿子类似曼哈顿距离,只能先确定这两个点再求
尝试转化为切比雪夫距离的变式,则这里变成了取min
而我们恰好要求最小距离,这就很可做了
同样并查集处理,按横,纵坐标分别排序后再枚举相邻的点更新最小距离
然后再同样分别排序后再扫一遍相邻点,在能取到最小距离的点所属并查集间连边
最后扫描这些并查集统计答案即可
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 9187201950435737471ll
#define N 100010
#define ll long long
#define pb push_back
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
ll x[N], y[N];
int head[N], size;
struct edge{int to, next; ll val;}e[300*350];
inline void add(int s, int t, ll w) {e[++size].to=t; e[size].val=w; e[size].next=head[s]; head[s]=size;}
namespace force{
ll minn=4557430888798830399ll, dis[N], cnt;
bool vis[N];
void spfa(int s) {
memset(dis, 0x3f, sizeof(ll)*(n+5));
dis[s]=0;
queue<int> q;
q.push(s);
int u;
while (q.size()) {
u=q.front(); q.pop();
vis[u]=0;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (dis[v] > dis[u]+e[i].val) {
dis[v] = dis[u]+e[i].val;
if (!vis[v]) q.push(v), vis[v]=1;
}
}
}
}
void solve() {
memset(head, -1, sizeof(head));
ll d;
for (int i=1; i<=n; ++i)
for (int j=i+1; j<=n; ++j) {
d = llabs(llabs(x[i]-x[j])-(llabs(y[i]-y[j])));
//if (d) minn=min(minn, d);
add(i, j, d), add(j, i, d);
}
//cout<<"minn: "<<minn<<endl;
for (int i=1; i<=n; ++i) {
spfa(i);
for (int j=1; j<=n; ++j) {
if (dis[j]==minn) ++cnt;
else if (dis[j] && dis[j]<minn) {
minn=dis[j], cnt=1;
}
}
}
if (minn>=4557430888798830399ll) {puts("-1"); exit(0);}
printf("%lld\n%lld\n", minn, cnt/2);
exit(0);
}
}
namespace task1{
ll ans=INF, cnt;
int fa[N], tot, lst[N], siz2[N], siz3[N];
ll mp[2010][2010];
struct edge{int from, to, next; ll val;}e[2010*2010];
inline void add(int s, int t, ll w) {e[++size].to=t; e[size].from=s; e[size].val=w; e[size].next=head[s]; head[s]=size;}
inline int find(int p) {return fa[p]==p?p:fa[p]=find(fa[p]);}
void solve() {
memset(head, -1, sizeof(head));
memset(mp, 127, sizeof(mp));
//cout<<ans<<' '<<mp[1][1]<<endl;
for (int i=1; i<=n; ++i) fa[i]=i;
for (int i=1; i<=n; ++i) siz2[i]=1;
ll d;
for (int i=1,f1,f2; i<=n; ++i)
for (int j=i+1; j<=n; ++j) {
f1=find(i), f2=find(j);
if (f1==f2) continue;
d = llabs(llabs(x[i]-x[j])-(llabs(y[i]-y[j])));
if (!d) fa[f2]=f1, siz2[f1]+=siz2[f2]; //, cout<<"uni: "<<i<<' '<<j<<' '<<siz2[f1]<<' '<<siz2[f2]<<endl;
add(i, j, d);
}
for (int i=1,f1,f2; i<=size; ++i) {
f1=find(e[i].from), f2=find(e[i].to);
if (f1==f2) continue;
if (!lst[f1]) lst[f1]=++tot, siz3[tot]=siz2[f1];
if (!lst[f2]) lst[f2]=++tot, siz3[tot]=siz2[f2];
mp[lst[f1]][lst[f2]]=min(mp[lst[f1]][lst[f2]], e[i].val);
mp[lst[f2]][lst[f1]]=min(mp[lst[f2]][lst[f1]], e[i].val);
}
//cout<<"tot: "<<tot<<endl;
//cout<<"siz: "; for (int i=1; i<=tot; ++i) cout<<siz3[i]<<' '; cout<<endl;
for (int i=1; i<=tot; ++i)
for (int j=i+1; j<=tot; ++j) {
if (mp[i][j]<INF) {
if (mp[i][j]==ans) cnt+=siz3[i]*siz3[j]; //, cout<<"+="<<siz3[i]<<' '<<siz3[j]<<endl;
else if (mp[i][j]<ans) {
ans=mp[i][j];
cnt=siz3[i]*siz3[j]; //, cout<<"recover: "<<siz3[i]<<' '<<siz3[j]<<endl;
}
}
}
if (ans==INF) {puts("-1"); exit(0);}
printf("%lld\n%lld\n", ans, cnt);
exit(0);
}
}
namespace task{
ll ans=INF, cnt;
int fa[N], tot, lst[N], siz[N];
vector<int> e[N];
struct point{ll x, y; int rk; inline void build(ll x_, ll y_, int r_) {x=x_; y=y_; rk=r_;}}p[N];
inline bool cmp1(point a, point b) {return a.x<b.x;}
inline bool cmp2(point a, point b) {return a.y<b.y;}
inline int find(int p) {return fa[p]==p?p:fa[p]=find(fa[p]);}
void solve() {
for (int i=1; i<=n; ++i) p[i].build(x[i]+y[i], x[i]-y[i], i);
for (int i=1; i<=n; ++i) fa[i]=i;
for (int i=1; i<=n; ++i) siz[i]=1;
ll d;
sort(p+1, p+n+1, cmp1);
for (int i=2,f1,f2; i<=n; ++i)
if (p[i].x==p[i-1].x) {
if (f1=find(p[i].rk),f2=find(p[i-1].rk),f1!=f2)
fa[f1]=f2, siz[f2]+=siz[f1];
}
else {
d=min(llabs(p[i].x-p[i-1].x), llabs(p[i].y-p[i-1].y));
if (d) ans=min(ans, d);
}
sort(p+1, p+n+1, cmp2);
for (int i=2,f1,f2; i<=n; ++i)
if (p[i].y==p[i-1].y) {
if (f1=find(p[i].rk),f2=find(p[i-1].rk),f1!=f2)
fa[f1]=f2, siz[f2]+=siz[f1];
}
else {
d=min(llabs(p[i].x-p[i-1].x), llabs(p[i].y-p[i-1].y));
if (d) ans=min(ans, d);
}
sort(p+1, p+n+1, cmp1);
for (int i=2; i<=n; ++i)
if (p[i].x!=p[i-1].x && min(llabs(p[i].x-p[i-1].x), llabs(p[i].y-p[i-1].y))==ans)
e[find(p[i-1].rk)].pb(find(p[i].rk)), e[find(p[i].rk)].pb(find(p[i-1].rk));
sort(p+1, p+n+1, cmp2);
for (int i=2; i<=n; ++i)
if (p[i].y!=p[i-1].y && min(llabs(p[i].x-p[i-1].x), llabs(p[i].y-p[i-1].y))==ans)
e[find(p[i-1].rk)].pb(find(p[i].rk)), e[find(p[i].rk)].pb(find(p[i-1].rk));
if (ans==INF) {puts("-1"); exit(0);}
for (int i=1,sz; i<=n; ++i) if (e[i].size()) {
sort(e[i].begin(), e[i].end());
sz=unique(e[i].begin(), e[i].end())-e[i].begin();
e[i].resize(sz);
for (auto it:e[i]) cnt+=siz[i]*siz[it];
}
printf("%lld\n%lld\n", ans, cnt/2);
exit(0);
}
}
signed main()
{
n=read();
for (int i=1; i<=n; ++i) x[i]=read(), y[i]=read();
//if (n<=300) force::solve();
//else task1::solve();
task::solve();
return 0;
}