想了俩小时转对偶图最小割是不是没救了。。。
画一下图,发现x到y的最短路相对于任意一条是的x,y在其两侧的边来说的话,一定:
a,b为这条边的两个端点
ans=min( min(dis(x,a)+dis(y,a),dis(x,b)+dis(y,b)) , min(dis(x,a)+dis(y,b)+1,dis(x,b)+dis(y,a)+1) )
本质上就是分类讨论。
这启发我们可以考虑沿这这条边进行拆分,拆成两个互不影响的子多边形,递归分治求解。
每次找到一条尽可能把两部分划分的均匀的边,拆位两个子多边形,进行分治。
为了方便代码实现,使用整体二分。
每次用bfs求出所有点到划分边的最短距离。
对于每一个询问如果位于这条边的同侧,递归求解。
否则,按照上述式子直接计算答案即可。
#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdlib>
#include<algorithm>
#define N 110000
#define L 100000
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline int read()
{
char ch=0;
int x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*flag;
}
struct edge{int to,nxt;}e[N*2];
int num,head[N];
void add(int x,int y)
{
e[++num]=(edge){y,head[x]};head[x]=num;
e[++num]=(edge){x,head[y]};head[y]=num;
}
struct link{int x,y;};
struct query{int x,y,id;};
queue<int>q;
int da[N],db[N],ans[N];
void bfs(int s,int *dis)
{
q.push(s);dis[s]=0;
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(to!=s&&!dis[to])
{
dis[to]=dis[x]+1;
q.push(to);
}
}
}
}
void solve(int n,vector<link>p,vector<query>q)
{
if(n<=0||q.empty())return;
vector<link>pl,pr;
vector<query>ql,qr;
int i,x,y,id,a=-1,b=-1,lenp=p.size(),lenq=q.size();
for(i=0;i<lenq;i++)
{
x=q[i].x;y=q[i].y;
if(x>y)swap(x,y);
ans[q[i].id]=min(ans[q[i].id],min(y-x,n-(y-x)));
}
for(i=0;i<lenp;i++)
{
x=p[i].x;y=p[i].y;
if(x>y)swap(x,y);
if(a==-1||max(abs(y-x),n-abs(y-x))<max(abs(b-a),n-abs(b-a)))a=x,b=y;
}
if(a==-1)return;
num=-1;for(i=1;i<=n;i++)head[i]=-1,da[i]=db[i]=0;
for(i=1;i<=n;i++)add(i,i%n+1);
for(i=0;i<lenp;i++)
{
x=p[i].x;y=p[i].y;
if(x>y)swap(x,y);
add(x,y);
if(x==a&&y==b)continue;
if((x>=b||x<=a)&&(y>=b||y<=a))pl.push_back((link){(x-b+1+n)%n,(y-b+1+n)%n});
if(a<=x&&y<=b)pr.push_back((link){x-a+1,y-a+1});
}
bfs(a,da);bfs(b,db);
for(i=0;i<lenq;i++)
{
x=q[i].x;y=q[i].y;id=q[i].id;
if(x>y)swap(x,y);
if((x>=b||x<=a)&&(y>=b||y<=a))ql.push_back((query){(x-b+1+n)%n,(y-b+1+n)%n,id});
else if(x>=a&&y<=b)qr.push_back((query){x-a+1,y-a+1,id});
else ans[id]=min(ans[id],min(min(da[x]+da[y],db[x]+db[y]),min(da[x]+db[y],da[y]+da[x])+1));
}
solve(a+n-b+1,pl,ql);
solve(b-a+1,pr,qr);
}
int main()
{
srand(time(0));
vector<link>p;vector<query>q;
int n=read(),m,i,x,y;
for(i=1;i<=n-3;i++)
{
x=read();y=read();
if(x>y)swap(x,y);
p.push_back((link){x,y});
}
m=read();
for(i=1;i<=m;i++)
{
x=read();y=read();
if(x>y)swap(x,y);
ans[i]=min(y-x,n-(y-x));
if(ans[i]>1)q.push_back((query){x,y,i});
}
solve(n,p,q);
for(i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}