[NEERC2015]Distance on Triangulation
考虑多边形三角剖分的实际意义,即一条对角线将一个多边形分为两个。很容易想到分治:每次在当前多边形中选出一条对角线使得两部分点数尽可能均匀,直到当前多边形为三角形为止。
询问时若两个点在选定的对角线同侧,则递归求解。若在两侧,由于三角剖分的性质,不会有任何一条边穿过此对角线。因此两点间最短路必然穿过对角线端点中的一个。bfs计算每个点到对角线距离即可。
细节注释在代码里
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define ld long double 4 using namespace std; 5 const int N=1002005; 6 int head[N],dis[2][N],p[N],b[N],h1[N],h2[N],can[N],ans[N],num,cnt,n,m; 7 struct asd{ 8 int next,to; 9 }a[N]; 10 struct edge{ 11 int x,y; 12 }e[N],t1[N],t2[N]; 13 struct Q{ 14 int x,y,id; 15 }q[N],f1[N],f2[N]; 16 void add(int x,int y){ 17 a[++num].next=head[x]; 18 head[x]=num; 19 a[num].to=y; 20 } 21 void bfs(int s,int l,int r,int *dis){ 22 cnt++; 23 for(int i=l;i<=r;i++) dis[p[i]]=0x3f3f3f3f,can[p[i]]=cnt;//打标记,只需遍历当前多边形上的点即可 24 dis[s]=0; queue<int>q; q.push(s); 25 while(!q.empty()){ 26 int k=q.front();q.pop(); 27 for(int i=head[k];i;i=a[i].next){ 28 if(dis[a[i].to]==0x3f3f3f3f&&can[a[i].to]==cnt){ 29 dis[a[i].to]=dis[k]+1; 30 q.push(a[i].to); 31 } 32 } 33 } 34 } 35 void solve(int pl,int pr,int el,int er,int ql,int qr){// p:点,e:边,q:询问 36 if(ql>qr||el>er||pl>pr) return ; 37 int num=0,now=0,Max=0x3f3f3f3f; 38 for(int i=pl;i<=pr;i++) 39 b[p[i]]=++num; // 将多边形上的点离散化 40 for(int i=el;i<=er;i++){ 41 int k=b[e[i].y]-b[e[i].x]+1; 42 if(max(k,pr-pl+3-k)<Max){ 43 Max=max(k,pr-pl+3-k); 44 now=i; 45 } 46 } //找分割边 47 bfs(e[now].x,pl,pr,dis[0]);bfs(e[now].y,pl,pr,dis[1]); 48 int n1=0,n2=0; 49 for(int i=ql;i<=qr;i++){ 50 if(q[i].x>e[now].x&&q[i].y<e[now].y) f1[++n1]=q[i]; 51 else if((q[i].x<e[now].x||q[i].x>e[now].y)&&(q[i].y<e[now].x||q[i].y>e[now].y)) f2[++n2]=q[i]; 52 else ans[q[i].id]=min(ans[q[i].id],min(dis[1][q[i].x]+dis[1][q[i].y],dis[0][q[i].x]+dis[0][q[i].y])); 53 } 54 for(int i=1;i<=n1;i++) q[ql+i-1]=f1[i]; 55 for(int i=1;i<=n2;i++) q[ql+n1+i-1]=f2[i]; 56 int n3=0,n4=0,k=p[pr+1],l=p[pr+2]; //对角线端点重复计算在两个多边形里,覆盖掉p[pr+1],p[pr+2]的值,待会要回溯 57 for(int i=pl;i<=pr;i++){ 58 if(p[i]>=e[now].x&&p[i]<=e[now].y) 59 h1[++n3]=p[i]; 60 if(p[i]<=e[now].x||p[i]>=e[now].y) 61 h2[++n4]=p[i]; 62 } 63 for(int i=1;i<=n3;i++) p[pl+i-1]=h1[i]; 64 for(int i=1;i<=n4;i++) p[pl+n3+i-1]=h2[i]; 65 int n5=0,n6=0; 66 for(int i=el;i<=er;i++){ 67 if(i==now) continue; 68 if(e[i].x>=e[now].x&&e[i].y<=e[now].y) t1[++n5]=e[i]; 69 else t2[++n6]=e[i]; 70 } 71 for(int i=1;i<=n5;i++) e[el+i-1]=t1[i]; 72 for(int i=1;i<=n6;i++) e[el+n5+i-1]=t2[i]; 73 solve(pl,pl+n3-1,el,el+n5-1,ql,ql+n1-1); 74 solve(pl+n3,pl+n3+n4-1,el+n5,el+n5+n6-1,ql+n1,ql+n1+n2-1); 75 p[pr+1]=k;p[pr+2]=l; //回溯 76 } 77 int main(){ 78 int i,j,k,l; 79 freopen("bsh.in","r",stdin); 80 freopen("bsh.out","w",stdout); 81 scanf("%d",&n); 82 for(i=1;i<=n;i++) p[i]=i; 83 for(i=1;i<n;i++) add(i,i+1),add(i+1,i); 84 add(1,n),add(n,1); 85 for(i=1;i<=n-3;i++){ 86 scanf("%d%d",&k,&l); 87 if(k>l) swap(k,l); 88 add(k,l);add(l,k); 89 e[i].x=k; 90 e[i].y=l; 91 } 92 scanf("%d",&m); 93 for(i=1;i<=m;i++){ 94 scanf("%d%d",&k,&l); 95 if(k>l) swap(k,l); 96 q[i].x=k; 97 q[i].y=l; 98 q[i].id=i; 99 ans[i]=min(l-k,n-(l-k)); //若k,l为同一个点(且此点不为三角划分的端点),分治不会处理 100 } //此时ans=0,不赋值也可过,这里是为了保险 101 solve(1,n,1,n-3,1,m); 102 for(i=1;i<=m;i++) 103 printf("%d\n",ans[i]); 104 return 0; 105 }