传送门
考试的时候只想到 \(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; }