bzoj 3073 [Pa2011]Journeys

http://www.elijahqi.win/archives/3246
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翻译
辣鸡蒟蒻elijahqi 自己yy的做法没法过样例.. 主要因为可能来回走 ..

所以建两棵线段树的同时需要将第二棵树全都指回来 这样的话相当于我可以来回在两颗线段树上走了这样恰好满足了原图的连通性

新连边的时候 新建一个节点 左边线段树节点向他连他连向右边线段树这样边数的复杂度从log^2降到log*2

最后输出答案的时候直接/2即可 因为虚点博主懒得写实数什么的了

#include
#include
#include
#include
#include
#include
#define pa pair
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=550000+10;
int rt1,rt2;
struct node{
    int left,right;
}tr1[N<<1],tr2[N<<2];
int id,n,m,p;
struct node1{
    int y,z,next;
}data[10000000];
int h[N<<2],num,dis[N<<2],cnt;bool flag[N<<2];
priority_queuevector,greater >q;
inline void insert1(int x,int y,int z){
    data[++num].y=y;data[num].z=z;data[num].next=h[x];h[x]=num;
}
inline void build1(int &x,int l,int r){
    x=++cnt;if (l==r){if (l==p) id=x;return;}int mid=l+r>>1;
    build1(tr1[x].left,l,mid);insert1(tr1[x].left,x,0);
    build1(tr1[x].right,mid+1,r);insert1(tr1[x].right,x,0);
}
inline void build2(int &x,int l,int r){
    x=++cnt;if (l==r) {return;}int mid=l+r>>1;
    build2(tr2[x].left,l,mid);insert1(x,tr2[x].left,0);
    build2(tr2[x].right,mid+1,r);insert1(x,tr2[x].right,0);
}
inline void modify1(int x,int l,int r,int l1,int r1){
    if (l1<=l&&r1>=r) {insert1(x,cnt,1);return;}int mid=l+r>>1;
    if (l1<=mid) modify1(tr1[x].left,l,mid,l1,r1);
    if (r1>mid) modify1(tr1[x].right,mid+1,r,l1,r1);
}
inline void modify2(int x,int l,int r,int l1,int r1){
    if (l1<=l&&r1>=r) {insert1(cnt,x,1);return;}int mid=l+r>>1;
    if (l1<=mid) modify2(tr2[x].left,l,mid,l1,r1);
    if (r1>mid) modify2(tr2[x].right,mid+1,r,l1,r1);
}
inline void print(int x,int l,int r){
    if (l==r) {printf("%d\n",dis[x]>>1);return;}int mid=l+r>>1;
    print(tr1[x].left,l,mid);print(tr1[x].right,mid+1,r);
}
inline void connect(int r1,int r2,int l,int r){
    insert1(r2,r1,0);if(l==r) return;int mid=l+r>>1;
    connect(tr1[r1].left,tr2[r2].left,l,mid);
    connect(tr1[r1].right,tr2[r2].right,mid+1,r);
}
int main(){
    freopen("bzoj3073.in","r",stdin);
    n=read();m=read();p=read();
    build1(rt1,1,n);build2(rt2,1,n);connect(rt1,rt2,1,n);
    for (int i=1;i<=m;++i){
        static int a,b,c,d;
        a=read();b=read();c=read();d=read();++cnt;
        modify1(rt1,1,n,a,b);modify2(rt2,1,n,c,d);++cnt;
        modify1(rt1,1,n,c,d);modify2(rt2,1,n,a,b);
    }
//  for (int i=1;i<=num;++i) printf("%d %d %d\n",data[i].x,data[i].y,data[i].z);
    memset(dis,0x3f,sizeof(dis));dis[id]=0;q.push(make_pair(0,id));
    while(!q.empty()){
        int x=q.top().second;q.pop();if (flag[x]) continue;flag[x]=1;
        for (int i=h[x];i;i=data[i].next){
            int y=data[i].y,z=data[i].z;
            if (dis[x]+z1,n);
    return 0;
}

你可能感兴趣的:(dijkstra,线段树)