「ROI 2018 Day 1」量子隐形传态

「ROI 2018 Day 1」量子隐形传态

题目大意:

\(N\times M\)的网格上给定\(K\)个点\(1\ldots K\),定义两点间的距离为\(\displaystyle 2^{\max\{|x_i-x_j|,|y_i-y_j|\}}\)

\(N,M,K\leq 10^4\),求\(1\)\(k\)的最短路,下文认为\(N,M\)同阶

如何存储距离

显然距离是一个不超过\(10^4\)位的二进制数,用\(\text{bitset}\)存下来

每一次转移需要维护一个位+1操作,比较大小操作,都可以\(O(\frac{N}{w})\)实现,其中\(\text{w}\)为压位数

\[\ \]

Lemma:

对于点\(A(x,y)\),将平面分为\(8\)个部分

Snipaste_2021-02-16_08-28-24.png

注意对于\(x'=x\)或者\(y'=y\)的区域一定要分离

则有:在任意一个平面区域中,有效的转移点一定是距离\((x,y)\)最近的点

简要证明:

对于\(A\)来说,切比雪夫距离相同的的点构成一条带

Snipaste_2021-02-16_08-39-07.png

设最近的点为\(B\),那么对于任意一个其它点\(C\),显然有\(dis(A,C)>dis(B,C),dis(A,C)>dis(A,B)\)

故走\(A\rightarrow B\rightarrow C\)不劣

快速完成转移

这样的\(B\)显然不唯一存在,每次转移需要的是\(\text{L}\)形的段

故可以对于每行每列用线段树优化区间连边

故得到一个\(O(K)\)点数,\(O(K\log K)\)边数的图

\(\text{Dijkstra}\)完成最短路,复杂度为\(O(K\log ^2 K\frac{N}{W})\)

ps: 这里没有考虑找到最近点的过程 ,下面的代码是直接暴力找的。。。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef pair <int,int> Pii;
#define reg register
#define pb push_back
#define mp make_pair
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,const T &b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,const T &b){ ((a<b)&&(a=b)); }

char IO;
int rd(){
	int s=0;
	while(!isdigit(IO=getchar()));
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return s;
}

const int N=30011,INF=1e9+10,U=10000,D=6;
bool Mbe;

int n,m,k;
int X[N],Y[N],pre[N],vis[N];
vector <Pii> E[N];
typedef unsigned long long ull;
struct Bitset{
	ull a[N/64+10];
	int l;
	void Add(int x){
		while(1) {
			ull t=a[x>>D];
			a[x>>D]+=1ull<<(x&63);
			if(t>a[x>>D]) x=((x>>D)+1)<<D;
			else break;
		}
		cmax(l,((x>>D)<<D)+63-__builtin_clzll(a[x>>D]));
	}
	bool operator < (const Bitset &__) const {
		if(__.l>10009) return 1;
		if(l!=__.l) return l<__.l;
		drep(i,(l>>D)+1,0) if(a[i]!=__.a[i]) return a[i]<__.a[i];
		return 0;
	}
} dis[N];
struct Queue{
	int s[N<<2],bit;
	void Up(int p) { s[p]=dis[s[p<<1]]<dis[s[p<<1|1]]?s[p<<1]:s[p<<1|1]; }
	void Build(){
		for(bit=1;bit<=n+1;bit<<=1);
		s[bit+1]=1;
		for(int p=bit+1;p;p>>=1) s[p]=1;
	}
	void push(int p) { for(s[p+bit]=p,p+=bit;p>>=1;) Up(p); }
	int top(){
		int res=s[1],p=s[1];
		for(s[p+=bit]=0;p>>=1;) Up(p);
		return res;
	}
} que;

int Dis(int x,int y) { return max(abs(X[x]-X[y]),abs(Y[x]-Y[y])); }
int Ans[N],Ac;
int Min[N][8];
int Dir(int u,int v){
	int x=X[v]-X[u],y=Y[v]-Y[u];
	if(y==0) return x>0?0:4;
	if(y>0) return x==0?2:(x>0?1:3);
	return x==0?6:(x>0?7:5);
}

typedef vector <int> V;
V A[N],B[N];
int rtx[N],rty[N],ls[N],rs[N];
int Build(const V &vec,int l,int r){
	if(l==r) return vec[l];
	int mid=(l+r)>>1,u=++n;
	ls[u]=Build(vec,l,mid),rs[u]=Build(vec,mid+1,r);
	E[u].pb(mp(ls[u],-1)),E[u].pb(mp(rs[u],-1));
	return u;
}
V Res;
void Que(const V &vec,int p,int l,int r,int ql,int qr){
	if(!p) return;
	if(ql<=vec[l] && vec[r]<=qr) return Res.pb(p);
	int mid=(l+r)>>1;
	if(ql<=vec[mid]) Que(vec,ls[p],l,mid,ql,qr);
	if(qr>=vec[mid+1]) Que(vec,rs[p],mid+1,r,ql,qr);
}
void AddX(int u,int x,int l,int r){
	int d=abs(x-X[u]);
	if(rtx[x]) Que(A[x],rtx[x],0,A[x].size()-1,l,r);
	for(int v:Res) {
		E[u].pb(mp(v,d));
	}
	Res.clear();
}
void AddY(int u,int y,int l,int r){
	int d=abs(y-Y[u]);
	if(rty[y]) Que(B[y],rty[y],0,B[y].size()-1,l,r);
	for(int v:Res) {
		E[u].pb(mp(v,d));
	}
	Res.clear();
}

void Init(){
	rep(i,1,k) A[X[i]].pb(i),B[Y[i]].pb(i);
	rep(i,1,U) {
		if(A[i].size()) {
			sort(A[i].begin(),A[i].end(),[&](int x,int y){ return Y[x]<Y[y]; });
			rtx[i]=Build(A[i],0,A[i].size()-1);
			for(int &j:A[i]) j=Y[j];
		}
		if(B[i].size()) {
			sort(B[i].begin(),B[i].end(),[&](int x,int y){ return X[x]<X[y]; });
			rty[i]=Build(B[i],0,B[i].size()-1);
			for(int &j:B[i]) j=X[j];
		}
	}
	rep(i,1,k) rep(j,0,7) Min[i][j]=INF;
	rep(i,1,k) rep(j,i+1,k){
		int d=Dir(i,j),dis=Dis(i,j);
		cmin(Min[i][d],dis);
		cmin(Min[j][(d+4)&7],dis);
	}
	rep(i,1,k) {
		if(Min[i][0]!=INF) AddX(i,X[i]+Min[i][0],Y[i],Y[i]);
		if(Min[i][1]!=INF) {
			AddX(i,X[i]+Min[i][1],Y[i]+1,Y[i]+Min[i][1]);
			AddY(i,Y[i]+Min[i][1],X[i]+1,X[i]+Min[i][1]);
		}
		if(Min[i][2]!=INF) AddY(i,Y[i]+Min[i][2],X[i],X[i]);
		if(Min[i][3]!=INF) {
			AddX(i,X[i]-Min[i][3],Y[i]+1,Y[i]+Min[i][3]);
			AddY(i,Y[i]+Min[i][3],X[i]-Min[i][3],X[i]-1);
		}
		if(Min[i][4]!=INF) AddX(i,X[i]-Min[i][4],Y[i],Y[i]);
		if(Min[i][5]!=INF) {
			AddX(i,X[i]-Min[i][5],Y[i]-Min[i][5],Y[i]-1);
			AddY(i,Y[i]-Min[i][5],X[i]-Min[i][5],X[i]-1);
		}
		if(Min[i][6]!=INF) AddY(i,Y[i]-Min[i][6],X[i],X[i]);
		if(Min[i][7]!=INF) {
			AddX(i,X[i]+Min[i][7],Y[i]-Min[i][7],Y[i]-1);
			AddY(i,Y[i]-Min[i][7],X[i]+1,X[i]+Min[i][7]);
		}
	}
}

bool Med;
int main(){
	fprintf(stderr,"%.2lf\n",(&Med-&Mbe)/1024.0/1024.0);
	n=rd(),m=rd(),k=rd(),n=k;
	rep(i,1,k) X[i]=rd(),Y[i]=rd();
	Init();
	que.Build();
	dis[0].Add(10111);
	rep(i,2,n) dis[i].Add(10110);
	while(que.s[1]) {
		int u=que.top();
		vis[u]=1;
		for(auto t:E[u]) {
			int v=t.first;
			Bitset w=dis[u]; if(~t.second) w.Add(t.second);
			if(w<dis[v]) dis[v]=w,que.push(v),pre[v]=u;
		}
	}

	for(int u=k;u;u=pre[u]) if(u<=k) Ans[++Ac]=u;
	printf("%d\n",Ac);
	drep(i,Ac,1) printf("%d ",Ans[i]);
}

posted @ 2021-02-16 08:55  chasedeath  阅读(304)  评论(0编辑  收藏  举报