Description
给定一个凸n边形,以及它的三角剖分。再给定q个询问,每个询问是一对凸多边行上的顶点(a,b),问点a最少经过多少条边(可以是多边形上的边,也可以是剖分上的边)可以到达点b。
Input
第一行一个整数n(n <= 50000),代表有n个点。点1,2,3,…,n是凸多边形上是顺时针排布的。
接下来n-3行,每行两个整数(x,y),代表(x,y)之间有一条剖分边。
接下来是一个整数q(q <= 100000),代表有q组询问。
接下来q行是两个整数(a,b)。
Output
输出q行,每行一个整数代表最少边数。
类似边分治,每次选一条边将多边形分为两部分,处理经过边的端点的路线,递归分治
#include<bits/stdc++.h> char buf[70007],*ptr=buf+70000; int G(){ if(ptr-buf==70000)fread(ptr=buf,1,70000,stdin); return *ptr++; } int _(){ int x=0; if(ptr-buf<69900){ while(*ptr<48)++ptr; while(*ptr>47)x=x*10+*ptr++-48; }else{ int c=G(); while(c<48)c=G(); while(c>47)x=x*10+c-48,c=G(); } return x; } const int N=100007,inf=0x3f3f3f3f,P=293999; int n,qp,idp=0; int deg[N],q[N],ql=0,qr=0,as[N]; std::vector<int>e0[N],ee[N]; struct Q{int w,id;}; std::vector<Q>qq[N]; Q*qs[N][2]; int sz[N],*lr[N][2],*et[N][2]; int p3[N][3]; void ae(int a,int b){ ++deg[b];++deg[a]; e0[a].push_back(b); e0[b].push_back(a); } struct hash_map{ int h[P][4]; int*operator()(int a,int b){ if(a>b)std::swap(a,b); int w=(a*1399+b*293)%P; while(h[w][0]){ if(h[w][0]==a&&h[w][1]==b)return h[w]+2; if((w+=1237)>=P)w-=P; } h[w][0]=a,h[w][1]=b; return h[w]+2; } }h1,h2; void chk(int a,int b){ if(a>b)std::swap(a,b); if(a==1&&b==n||a+1==b)return; int*w=h1(a,b); if(w[0]){ int x=idp,y=w[0]; ee[x].push_back(y); ee[y].push_back(x); int*c=h2(x,y); c[0]=a;c[1]=b; }else w[0]=idp; } int ss[N][2],sp,tk=1,ed[N],ed2[N]; int ps[N],pp=0; void ins(int a){ for(int t=0;t<3;++t){ int w=p3[a][t]; if(ed2[w]!=tk)ed2[ps[pp++]=w]=tk; } } void f2(int w,int pa){ sz[w]=1; ed[w]=tk; ss[sp][0]=w,ss[sp++][1]=pa; for(int*l=lr[w][0],*r=lr[w][1];l!=r;++l){ int u=*l; if(u==pa)continue; f2(u,w); sz[w]+=sz[u]; } } void dele(int a,int b){ for(int*l=lr[a][0],*r=lr[a][1];l!=r;++l)if(*l==b){ *l=*--lr[a][1]; return; } } int min(int a,int b){return a<b?a:b;} void mins(int&a,int b){if(a>b)a=b;} int d1[N],d2[N],dd1[N],dd2[N],dk=1; bool qd[N]; void bfs(int w,int*d,int*dd){ ql=qr=0; dd[q[++qr]=w]=dk,d[w]=0; while(ql!=qr){ w=q[++ql]; for(int*l=et[w][0],*r=et[w][1];l!=r;++l){ int u=*l; if(ed2[u]==tk&&dd[u]!=dk)dd[q[++qr]=u]=dk,d[u]=d[w]+1; } } } void f1(int w){ ++tk; pp=0; sp=0; f2(w,0); int SZ=sz[w]; if(SZ>1){ int mx=0,p1=w,p2=0; for(int i=0;i<sp;++i){ int u=ss[i][0],mv=min(sz[u],SZ-sz[u]); if(mv>mx)mx=mv,p1=u,p2=ss[i][1]; ins(u); } dele(p1,p2); dele(p2,p1); int*ns=h2(p1,p2); ++dk; bfs(ns[0],d1,dd1);bfs(ns[1],d2,dd2); for(int i=0;i<pp;++i){ int u=ps[i]; int d1u=d1[u]; int d2u=d2[u]; for(Q*l=qs[u][0],*r=qs[u][1];l!=r;++l){ int v=l->w; if(qd[v])*l--=*(qs[u][1]=--r); else if(ed2[v]==tk){ int d1v=d1[v]; int d2v=d2[v]; mins(as[l->id],min(min(d1u+d1v,d2u+d2v),min(d1u+d2v+1,d2u+d1v+1))); } } } qd[ns[0]]=qd[ns[1]]=1; for(int d=0;d<2;++d)qs[ns[d]][0]=qs[ns[d]][1]; f1(p1);f1(p2); } } int main(){ n=_(); for(int i=1,a,b;i<=n-3;++i){ a=_();b=_(); ae(a,b); } for(int i=1;i<=n;++i)ae(i,i==n?1:i+1); for(int i=1;i<=n;++i){ et[i][0]=e0[i].data(); et[i][1]=et[i][0]+e0[i].size(); } for(int i=1;i<=n;++i)if(deg[i]==2)q[++qr]=i; while(ql!=qr){ int w=q[++ql]; if(deg[w]!=2)break; deg[w]=0; int cs[3],cp=0; cs[cp++]=w; for(int*l=et[w][0],*r=et[w][1];l!=r;++l){ int u=*l; if(!deg[u])continue; cs[cp++]=u; if(2==--deg[u])q[++qr]=u; } ++idp; for(int i=0;i<3;++i){ for(int j=0;j<i;++j)chk(cs[i],cs[j]); p3[idp][i]=cs[i]; } } for(int i=1;i<=idp;++i){ lr[i][0]=ee[i].data(); lr[i][1]=lr[i][0]+ee[i].size(); } qp=_(); for(int i=0;i<qp;++i){ int x=_(),y=_(); if(x==y)continue; if(x>y)std::swap(x,y); if(x==1&&y==n||x+1==y||h1(x,y)[0]){ as[i]=1; continue; } as[i]=inf; qq[x].push_back((Q){y,i}); qq[y].push_back((Q){x,i}); } for(int i=1;i<=idp;++i){ qs[i][0]=qq[i].data(); qs[i][1]=qs[i][0]+qq[i].size(); } f1(1); for(int i=0;i<qp;++i)printf("%d\n",as[i]); return 0; }