1. 程式人生 > >正睿 2019 省選附加賽 Day1 T2 開開車

正睿 2019 省選附加賽 Day1 T2 開開車

想了倆小時轉對偶圖最小割是不是沒救了。。。
畫一下圖,發現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;
}