[2018雅礼省选集训3-25]bsh 分治最短路

因为是三角剖分,所以每一条对角线都把多边形分成两部分,于是考虑分治。
先找到一条把多边形分得比较均匀的对角线,对两个端点做一下bfs,处理掉起点和终点分别在这条对角线两侧的询问(分经过某个点或者经过这条边三种情况更新),然后继续分治直到三角形为止。
选对角线的时候直接选最远的即可。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 52010
#define fs first
#define sc second
#define chkmin(a,b) a=min(a,b)
#define in(x) (x>dx&&x<dy)
#define out(x) (x<dx||x>dy)
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,a[N],b[N],d1[N],d2[N],vis[N],dl[N];
int read()
{
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*f; 
}
struct edge
{
    int t;bool b;
    edge *next;
}*con[N];
struct node
{
    int x,y,id,ans;
}q[N<<1],s[N<<1];
bool cmp(node p,node q)
{
    return p.id<q.id;
}
void ins(int x,int y,bool b)
{
    edge *p=new edge;
    p->t=y;p->b=b;
    p->next=con[x];
    con[x]=p;
}
void bfs(int S,int l,int r,int *d)
{
    for(int i=l;i<=r;i++)
        d[a[i]]=inf;
    d[S]=0;dl[1]=S;
    for(int hd=1,tl=1,v=S;hd<=tl;v=dl[++hd])
        for(edge *p=con[v];p;p=p->next)
            if(vis[p->t]&&d[p->t]==inf)
                d[p->t]=d[v]+1,dl[++tl]=p->t;
}
void solve(int l,int r,int L,int R)
{
    if(l>r||L>R) return ;
    for(int i=l;i<=r;i++)
        vis[a[i]]=i-l+1;
    int o=r-l+1;
    if(o<=3)
    {
        for(int i=l;i<=r;i++)
        {
            bfs(a[i],l,r,d1);
            for(int j=L;j<=R;j++)
                if(q[j].x==a[i]) chkmin(q[j].ans,d1[q[j].y]);
        }
        return ;
    }
    int dx,dy,d=0;
    for(int i=l;i<=r;i++)
        for(edge *p=con[a[i]];p;p=p->next)
            if(p->b&&vis[p->t]>vis[a[i]])
            {
                int tmp=min(vis[p->t]-vis[a[i]],o-vis[p->t]+vis[a[i]]);
                if(tmp>d) d=tmp,dx=a[i],dy=p->t;
            }
    if(d==0)return ;    
    bfs(dx,l,r,d1);bfs(dy,l,r,d2);
    for(int i=L;i<=R;i++)
        chkmin(q[i].ans,min(min(d1[q[i].x]+d2[q[i].y],d1[q[i].y]+d2[q[i].x])+1,min(d1[q[i].x]+d1[q[i].y],d2[q[i].y]+d2[q[i].x])));
    int Top=L-1,mT,nT,top=l-1,mt,nt;

    for(int i=L;i<=R;i++)
        if(in(q[i].x)&&in(q[i].y)) s[++Top]=q[i];
    mT=Top;
    for(int i=L;i<=R;i++)
        if(out(q[i].x)&&out(q[i].y)) s[++Top]=q[i];
    nT=Top; 
    for(int i=L;i<=R;i++)
        if(!(in(q[i].x)&&in(q[i].y))&&!(out(q[i].x)&&out(q[i].y))) s[++Top]=q[i];
    for(int i=L;i<=R;i++)
        q[i]=s[i];

    for(int i=l;i<=r;i++)
        if(in(a[i])&&in(a[i])) b[++top]=a[i];
    mt=top;
    for(int i=l;i<=r;i++)
        if(out(a[i])&&out(a[i])) b[++top]=a[i];
    nt=top; 
    for(int i=l;i<=r;i++)
        if(!(in(a[i])&&in(a[i]))&&!(out(a[i])&&out(a[i])))   b[++top]=a[i];
    for(int i=l;i<=r;i++)
        a[i]=b[i];  
    for(int i=l;i<=r;i++)
        vis[a[i]]=0;    
    solve(l,mt,L,mT);
    solve(mt+1,nt,mT+1,nT); 
}
int main()
{
    n=read();
    for(int i=1;i<n;i++)
        ins(i,i+1,0),ins(i+1,i,0);
    ins(1,n,0);ins(n,1,0);  
    for(int i=1;i<=n-3;i++)
    {
        int x=read(),y=read();
        ins(x,y,1);ins(y,x,1);
    }
    m=read();
    for(int i=1;i<=m;i++)
    {
        q[i].x=read();q[i].y=read();
        q[i].id=i;
        if(q[i].x>q[i].y) swap(q[i].x,q[i].y);
        q[i].ans=min(q[i].y-q[i].x,n-q[i].y+q[i].x);

    }
    for(int i=1;i<=n;i++)
        a[i]=i;
    solve(1,n,1,m);
    sort(q+1,q+m+1,cmp);
    for(int i=1;i<=m;i++)
        printf("%d\n",q[i].ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值