题解 星空

传送门

  • 遇到形如 \(| |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;
}
posted @ 2021-08-16 06:13  Administrator-09  阅读(16)  评论(0编辑  收藏  举报