bzoj5140 [Usaco2017 Dec]A Pie for a Pie(最短路+set)

其实就是建图,多源点最短路。但是呢边数最坏是 O(n2) 级别的,暴力建图会gg(不过数据水,跑的还贼快,快卡掉它吧(逃)
我们发现对于一个点x,他能连向的点是点权在[x,x+d]范围内的点,边权均为1,于是我们可以直接bfs,每个点只入队一次。每次快速的找到未入队的点中能连向的点,并删除即可。我们可以用一个set来支持这个操作。复杂度O(nlogn)

不会自定义比较函数gg,只好set+pair,就需要注意pair比大小的一些细节,一开始都取个负,就可以直接lower_bound了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>
#include <utility>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 200010
#define pa pair<int,int>
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,D,a[N],b[N],dis[N];
queue<int>q;
set<pa>sta,stb;set<pa>::iterator it;
int main(){
//  freopen("a.in","r",stdin);
    n=read();D=read();memset(dis,-1,sizeof(dis));
    for(int i=1;i<=n*2;++i) a[i]=-read(),b[i]=-read();
    for(int i=1;i<=n;++i){
        if(!b[i]) dis[i]=1,q.push(i);
        else sta.insert(make_pair(b[i],i));
        if(!a[n+i]) dis[n+i]=1,q.push(n+i);
        else stb.insert(make_pair(a[n+i],n+i));
    }while(!q.empty()){
        int x=q.front();q.pop();
        if(x<=n){//A<-B
            while(1){
                it=stb.lower_bound(make_pair(a[x],0));
                if(it==stb.end()||it->first>a[x]+D) break;
                int y=it->second;stb.erase(*it);dis[y]=dis[x]+1;q.push(y);  
            }
        }else{//B<-A
            while(1){
                it=sta.lower_bound(make_pair(b[x],0));
                if(it==sta.end()||it->first>b[x]+D) break;
                int y=it->second;sta.erase(*it);dis[y]=dis[x]+1;q.push(y);
            }
        }
    }for(int i=1;i<=n;++i) printf("%d\n",dis[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值