BZOJ3073: [Pa2011]Journeys
题解: 暴力建图当然gg 我们考虑用线段树分块建图的思想 因为涉及到两个区间 对着建图 一个线段树不够 考虑用两个线段树 一个作为出树(出树儿子向父亲连边) 一个作为入树(父亲向儿子连边) 每次出树向入树连边 这样建图的话也是mlogn^2的 显然还可以优化 我们采用对于每次连边 用一个超级大源点 这样的话每次连边为log^n级别的 然后对于入树而言 他可以和出树平行连边 这样的话 在本质上 还是两个区间直接产生贡献=>等价于从出树的x节点->入树的y节点->出树的y节点 这样连边跑spfa统计入树答案即可
#include <bits/stdc++.h> #define mp make_pair const int MAXN=8e5+10; const int inf=1e9; using namespace std; vector<pair<int,int> >vec[MAXN<<3]; int pos[MAXN],sz,S,n,m,p; void built(int rt,int l,int r){ if(l==r){pos[l]=rt;return ;} vec[rt<<1].push_back(mp(rt,0)); vec[rt<<1|1].push_back(mp(rt,0)); int mid=(l+r)>>1; built(rt<<1,l,mid); built(rt<<1|1,mid+1,r); } void built1(int rt,int l,int r){ vec[rt+sz].push_back(mp(rt,0)); if(l==r)return ; vec[rt+sz].push_back(mp((rt<<1)+sz,0));vec[rt+sz].push_back(mp((rt<<1|1)+sz,0)); int mid=(l+r)>>1; built1(rt<<1,l,mid); built1(rt<<1|1,mid+1,r); } void addedge(int rt,int l,int r,int ql,int qr,int vul){ if(ql<=l&&r<=qr){ if(vul>0)vec[rt].push_back(mp(S,1)); else vec[S].push_back(mp(rt+sz,0)); return ; } int mid=(l+r)>>1; if(ql<=mid)addedge(rt<<1,l,mid,ql,qr,vul); if(qr>mid)addedge(rt<<1|1,mid+1,r,ql,qr,vul); } int dis[MAXN<<3];bool vis[MAXN<<3]; queue<int>que; void spfa(int t){ for(int i=0;i<=S;i++)dis[i]=inf,vis[i]=0; que.push(t);vis[t]=1;dis[t]=dis[t+sz]=0; while(!que.empty()){ int t1=que.front();que.pop();vis[t1]=0; for(int i=0;i<vec[t1].size();i++){ if(dis[vec[t1][i].first]>dis[t1]+vec[t1][i].second){ dis[vec[t1][i].first]=dis[t1]+vec[t1][i].second; if(!vis[vec[t1][i].first]){vis[vec[t1][i].first]=1;que.push(vec[t1][i].first);} } } } } int main(){ scanf("%d%d%d",&n,&m,&p);S=(n<<3); sz=(n<<2);built(1,1,n);built1(1,1,n); int a,b,c,d; for(int i=1;i<=m;i++){ scanf("%d%d%d%d",&a,&b,&c,&d); S++; addedge(1,1,n,a,b,1);addedge(1,1,n,c,d,0); S++; addedge(1,1,n,c,d,1);addedge(1,1,n,a,b,0); } spfa(pos[p]); for(int i=1;i<=n;i++)printf("%d\n",dis[pos[i]+sz]); }
3073: [Pa2011]Journeys
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 634 Solved: 191
[Submit][Status][Discuss]
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
1 2 4 5
5 5 4 4
1 1 3 3
Sample Output
1
1
2
0
1
1
2
0
1