【PA2011】【BZOJ3073】Journeys

Description

Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路。N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路。Seter保证一条道路不会修建两次,也保证不会有一个国家与自己之间有道路。
Seter好不容易建好了所有道路,他现在在位于P号的首都。Seter想知道P号国家到任意一个国家最少需要经过几条道路。当然,Seter保证P号国家能到任意一个国家。

注意:可能有重边
Input

第一行三个数N,M,P。N<=500000,M<=100000。
后M行,每行4个数A,B,C,D。1<=A<=B<=N,1<=C<=D<=N。

Output

N行,第i行表示P号国家到第i个国家最少需要经过几条路。显然第P行应该是0。

Sample Input

5 3 4

1 2 4 5

5 5 4 4

1 1 3 3

Sample Output

1

1

2

0

1
HINT

Source

seter翻译

线段树优化建图的最短路.(咦这个真的算线段树优化建图吗..我个人的定义可能不太严谨
可能卡内存..最后试了试边数组开300W就能过

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#define MAXN 500010
#define GET (ch>='0'&&ch<='9')
#define lchild rt<<1,l,mid
#define rchild rt<<1|1,mid+1,r
#define ln rt<<1
#define rn rt<<1|1
using namespace std;
int n,m,p,top,tp,cnt;
int a,b,c,d,tl,tr;
set<int> s;
set<int>::iterator it,sta[MAXN];
inline void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
int root[MAXN],dis[MAXN];
struct edge {   int al,ar;edge *next;   }e[MAXN*6],*prev[MAXN*2+50000];
inline void build(int rt=1,int l=1,int r=n)
{
    if (l==r)   {   root[l]=rt;return;  }
    int mid=(l+r)>>1;build(lchild);build(rchild);
}
inline void insert(int rt,int l,int r,int L,int R)
{
    int mid=(L+R)>>1;
    if (l<=L&&r>=R) {   e[++top].al=tl;e[top].ar=tr;e[top].next=prev[rt];prev[rt]=&e[top];return;   }
    if (r<=mid) insert(ln,l,r,L,mid);
    else    if (l>mid)  insert(rn,l,r,mid+1,R);
    else    insert(ln,l,mid,L,mid),insert(rn,mid+1,r,mid+1,R);
}
int main()
{
    int x,t;
    for (in(n),in(m),in(p),build();m;m--)
        in(a),in(b),in(c),in(d),
        tl=c,tr=d,insert(1,a,b,1,n),
        tl=a,tr=b,insert(1,c,d,1,n);
    queue<int>  q;q.push(p);
    for (int i=1;i<=n+1;i++)    if (i!=p)   s.insert(i);
    while (!q.empty())
    {
        x=q.front();t=dis[x];q.pop();x=root[x];
        for (;x;prev[x]=0x0,x>>=1)
            for (edge *i=prev[x];i;i=i->next)
            {
                for (cnt=0,it=s.lower_bound(i->al);*it<=i->ar;it++) dis[*it]=t+1,q.push(*it),sta[++cnt]=it;
                while (cnt) s.erase(sta[cnt--]);
            }
    }
    for (int i=1;i<=n;i++)  printf("%d\n",dis[i]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值