正睿 2019 省選附加賽 Day1 T2 開開車
阿新 • • 發佈:2018-12-06
想了倆小時轉對偶圖最小割是不是沒救了。。。
畫一下圖,發現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; }