[loj2846]量子隐形传态

假设当前位于$A(x,y)$,将坐标系按上下左右、(左/右)(上/下)分为八块

结论:存在一组最优解,每次均移动到某一块中距离$(x,y)$最近的某点

记$d(A,B)$为$A$到$B$的切比雪夫距离,即$\max(|x_{A}-x_{B}|,|y_{A}-y_{B}|)$

假设移动到的点为$B$,而该块中最近的某点为$C$,则$d(A,C),d(B,C)<d(A,B)$

(前者根据定义显然,后者考虑$dis(A,B)$中较大的一维即可)

换言之,有$2^{d(A,C)}+2^{d(B,C)}\le 2^{d(A,B)}$,从$C$经过不劣,即得证

上下左右四部分显然该点唯一,可以直接连边

(左/右)(上/下)四部分建立一个虚点,并从虚点向这些取到最近距离的点连边

此时,虽然图中有$O(n^{2})$条边,但实际有边权的边仅有$O(n)$条

考虑dijkstra求最短路,并用(手写)bitset维护距离

对于带权边,可以$O(\frac{n}{\omega})$更新;对于不带权边,可以直接更新,且至多$O(n)$次

每次取出最小距离可以用堆/线段树维护,单次更新的复杂度为$O(\frac{n\log n}{\omega})$

综上,总复杂度为$O(n^{2}+\frac{n^{2}\log n}{\omega})$,可以通过

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define L (k<<1)
  4 #define R (L|1)
  5 #define mid (l+r>>1)
  6 typedef unsigned long long ull;
  7 const int N=10100,M=90005,oo=0x3f3f3f3f;
  8 int n,V,x[N],y[N],a[N][8],id[N][8],vis[M],from[M],f[M<<2];
  9 ull d[M][N>>6];pair<int,int>pos[M];
 10 vector<int>ans,v[N][8];
 11 int dis(int i,int j){
 12     return max(abs(x[i]-x[j]),abs(y[i]-y[j]));
 13 }
 14 int dir(int i,int j){
 15     int dx=(x[i]==x[j] ? 2 : x[i]<x[j]);
 16     int dy=(y[i]==y[j] ? 2 : y[i]<y[j]);
 17     return dx*3+dy;
 18 }
 19 bool cmp(int x,int y){
 20     for(int i=(N>>6)-1;i>=0;i--)
 21         if (d[x][i]!=d[y][i])return d[x][i]<d[y][i];
 22     return 0;
 23 }
 24 void add(int x,int y){
 25     memcpy(d[0],d[x],sizeof(d[0]));
 26     if (y<0)return;
 27     ull s=((ull)1<<(y&63));
 28     y>>=6,d[0][y]+=s;
 29     if (d[0][y]<d[x][y]){
 30         y++;
 31         while (d[0][y]==(ull)-1)d[0][y++]=0;
 32         d[0][y]++;
 33     }
 34 }
 35 void up(int k){
 36     if ((!f[L])||(!f[R]))f[k]=(f[L]|f[R]);
 37     else f[k]=(cmp(f[L],f[R]) ? f[L] : f[R]);
 38 }
 39 void build(int k,int l,int r){
 40     if (l==r){
 41         f[k]=(l==1);
 42         return;
 43     }
 44     build(L,l,mid),build(R,mid+1,r);
 45     up(k);
 46 }
 47 void update(int k,int l,int r,int x,int y){
 48     if (l==r){
 49         f[k]=y;
 50         return;
 51     }
 52     if (x<=mid)update(L,l,mid,x,y);
 53     else update(R,mid+1,r,x,y);
 54     up(k);
 55 }
 56 int main(){
 57     scanf("%*d%*d%d",&n);
 58     for(int i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]);
 59     V=n;
 60     memset(a,0x3f,sizeof(a));
 61     for(int i=1;i<=n;i++){
 62         for(int j=1;j<=n;j++){
 63             int D=dis(i,j),P=dir(i,j);
 64             if (P==8)continue;
 65             if (D<a[i][P])a[i][P]=D,v[i][P].clear();
 66             if (D==a[i][P])v[i][P].push_back(j);
 67         }
 68         for(int P=0;P<8;P++)
 69             if (!v[i][P].empty()){
 70                 id[i][P]=++V;
 71                 pos[V]=make_pair(i,P);
 72             }
 73     }
 74     for(int i=2;i<=V;i++)d[i][(N>>6)-1]=-1;
 75     build(1,1,V);
 76     while (1){
 77         int k=f[1];
 78         if (k==n)break;
 79         if (k<=n){
 80             for(int P=0;P<8;P++)
 81                 if ((!vis[id[k][P]])&&(id[k][P])){
 82                     add(k,a[k][P]);
 83                     if (cmp(0,id[k][P])){
 84                         from[id[k][P]]=k;
 85                         memcpy(d[id[k][P]],d[0],sizeof(d[0]));
 86                         update(1,1,V,id[k][P],id[k][P]);
 87                     }
 88                 }
 89         }
 90         else{
 91             int P=pos[k].second;
 92             for(int i:v[pos[k].first][P])
 93                 if (!vis[i]){
 94                     from[i]=k,vis[i]=1;
 95                     memcpy(d[i],d[k],sizeof(d[i]));
 96                     update(1,1,V,i,i);
 97                 }
 98         }
 99         vis[k]=1,update(1,1,V,k,0);
100     }
101     for(int i=n;i!=1;i=from[i])
102         if (i<=n)ans.push_back(i);
103     ans.push_back(1);
104     reverse(ans.begin(),ans.end());
105     printf("%d\n",ans.size());
106     for(int i:ans)printf("%d ",i);
107     return 0;
108 } 
View Code

 

posted @ 2022-10-21 17:36  PYWBKTDA  阅读(88)  评论(0编辑  收藏  举报