BZOJ4449: [Neerc2015]Distance on Triangulation
$n \leq 50000$的凸多边形,给一个三角剖分,$q \leq 100000$组询问每次问两点之间最短路。
凸多边形是个特殊的图,一般图找单源最短路已经有精美的算法了。然而多组询问呢?
其实关于路径统计、路径询问的问题,在树上常用的是点分治,每次能统计经过根节点的路径,然后再尽量把他分成较大值较小的两块。在这里可以采用同样的方法。
一:凸多边形三角剖分的对偶图是一棵树,直接在树上点分。
二:同样采用“尽量分成较大值较小的两块”的想法,每次选一条“中中”的剖分边,由于经过这条边的剖分边的路径的最短路一定由这条剖分边两个端点到其他点的最短路拼凑而来,因此可以回答所有经过他的询问。
OK看起来方法二比较好写嘛。。。
每次分治需要三个信息:剖分边,当前多边形外围的点,以及能回答的询问。
注意:每次分治完,左右两边的点会比原来多两个(剖分边的),最多进行n次分治,因此空间要开三倍。为了避免因为多点使左边信息覆盖到右边,可以先对右边进行分治再往左边。
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 //#include<time.h> 6 //#include<complex> 7 #include<algorithm> 8 #include<stdlib.h> 9 using namespace std; 10 11 int n,m; 12 #define maxn 300011 13 struct Node{int x,y,id;}qq[maxn],line[maxn],h1[maxn],h2[maxn]; int poi[maxn],h3[maxn],h4[maxn]; 14 struct Edge{int to,next;}edge[maxn<<1]; int first[maxn],le=2; 15 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;} 16 void insert(int x,int y) {in(x,y); in(y,x);} 17 18 int disx[maxn],disy[maxn]; 19 int que[maxn],head,tail; 20 int find(int pl,int pr,int x) 21 { 22 int L=pl,R=pr; 23 while (L<R) 24 { 25 int mid=(L+R)>>1; 26 if (poi[mid]>=x) R=mid; 27 else L=mid+1; 28 } 29 return L; 30 } 31 void bfs(int s,int pl,int pr,int *dis) 32 { 33 head=tail=0; 34 for (int i=pl;i<=pr;i++) dis[poi[i]]=0x3f3f3f3f; 35 que[tail++]=s; dis[s]=0; 36 while (head!=tail) 37 { 38 int now=que[head++]; 39 for (int i=first[now];i;i=edge[i].next) 40 { 41 Edge &e=edge[i]; if (poi[find(pl,pr,e.to)]!=e.to) continue; 42 if (dis[e.to]==0x3f3f3f3f) dis[e.to]=dis[now]+1,que[tail++]=e.to; 43 } 44 } 45 } 46 47 int ans[maxn]; 48 void solve(int xl,int xr,int pl,int pr,int ql,int qr) 49 { 50 if (xl>xr || pl>pr || ql>qr) return; 51 int Min=2e9,who=0; 52 for (int i=xl,tmp=pr-pl+1,tt;i<=xr;i++) 53 { 54 int tx=find(pl,pr,line[i].x),ty=find(pl,pr,line[i].y); 55 if (tx>ty) {tx^=ty; ty^=tx; tx^=ty;} 56 if ((tt=max(ty-tx,tx+tmp-ty))<Min) Min=tt,who=i; 57 } 58 bfs(line[who].x,pl,pr,disx); bfs(line[who].y,pl,pr,disy); 59 int t1,t2,t3,t4,t5,t6; t1=t2=t3=t4=t5=t6=0; 60 61 for (int i=ql;i<=qr;i++) 62 { 63 if ((qq[i].x==line[who].x && qq[i].y==line[who].y) || (qq[i].x==line[who].y && qq[i].y==line[who].x)) 64 {ans[qq[i].id]=1; continue;} 65 ans[qq[i].id]=min(ans[qq[i].id],min(min(disx[qq[i].x]+disx[qq[i].y],disy[qq[i].x]+disy[qq[i].y]), 66 min(disx[qq[i].x]+1+disy[qq[i].y],disx[qq[i].y]+1+disy[qq[i].x]))); 67 if (qq[i].x>line[who].x && qq[i].y<line[who].y) h1[++t1]=qq[i]; 68 if ((qq[i].y>line[who].y || qq[i].y<line[who].x) && (qq[i].x>line[who].y || qq[i].x<line[who].x)) h2[++t2]=qq[i]; 69 } 70 for (int i=1;i<=t1;i++) qq[ql+i-1]=h1[i]; 71 for (int i=1;i<=t2;i++) qq[ql+t1+i-1]=h2[i]; 72 73 for (int i=pl;i<=pr;i++) 74 { 75 if (poi[i]>=line[who].x && poi[i]<=line[who].y) h3[++t3]=poi[i]; 76 if (poi[i]<=line[who].x || poi[i]>=line[who].y) h4[++t4]=poi[i]; 77 } 78 for (int i=1;i<=t3;i++) poi[pl+i-1]=h3[i]; 79 for (int i=1;i<=t4;i++) poi[pl+t3+i-1]=h4[i]; 80 81 for (int i=xl;i<=xr;i++) if (i!=who) 82 { 83 if (line[i].x>=line[who].x && line[i].x<=line[who].y && line[i].y>=line[who].x && line[i].y<=line[who].y) 84 h1[++t5]=line[i]; 85 else h2[++t6]=line[i]; 86 } 87 for (int i=1;i<=t5;i++) line[xl+i-1]=h1[i]; 88 for (int i=1;i<=t6;i++) line[xl+t5+i-1]=h2[i]; 89 90 solve(xl+t5,xl+t5+t6-1,pl+t3,pl+t3+t4-1,ql+t1,ql+t1+t2-1); 91 solve(xl,xl+t5-1,pl,pl+t3-1,ql,ql+t1-1); 92 } 93 94 int main() 95 { 96 scanf("%d",&n); 97 for (int i=1;i<=n-3;i++) 98 { 99 scanf("%d%d",&line[i].x,&line[i].y); insert(line[i].x,line[i].y); 100 if (line[i].x>line[i].y) {line[i].x^=line[i].y; line[i].y^=line[i].x; line[i].x^=line[i].y;} 101 } 102 for (int i=1;i<n;i++) insert(i,i+1); insert(1,n); 103 scanf("%d",&m); 104 for (int i=1;i<=m;i++) 105 { 106 scanf("%d%d",&qq[i].x,&qq[i].y); 107 if (qq[i].x>qq[i].y) {qq[i].x^=qq[i].y; qq[i].y^=qq[i].x; qq[i].x^=qq[i].y;} 108 ans[i]=min(qq[i].y-qq[i].x,qq[i].x+n-qq[i].y); 109 qq[i].id=i; 110 } 111 for (int i=1;i<=n;i++) poi[i]=i; 112 solve(1,n-3,1,n,1,m); 113 for (int i=1;i<=m;i++) printf("%d\n",ans[i]); 114 return 0; 115 }