bzoj 3073: [Pa2011]Journeys 线段树优化建图+堆优化dij
2017-04-17 17:12
417 查看
题意
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号国家能到任意一个国家。
N<=500000,M<=100000。
分析
这题感觉有点像SCOI 2016萌萌哒,也是用类似这样的思想来优化。我们搞两颗线段树,第一棵每个节点往他的父节点连长度为0的边;第二棵每个节点往他的儿子连长度为0的边。然后第二棵线段树每个节点往第一棵线段树的对应节点连长度为0的边。
每加入一条边,我们就新建一个节点,把第一棵线段树上对应区间向该节点连长度为1的边,该节点向第二课线段树连长度为1的边。
然后跑堆优化dij就好了。
这样建图就可以把第一棵线段树的叶节点看做原来的点。至于为什么这样是对的,手玩一下就好了。
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int N=500005; const int M=3000005; const int inf=0x3f3f3f3f; int cnt,last[M],sz,dis[M],pos ,p,n,m; struct data { int num,val; bool operator < (const data &a) const { return val>a.val; } }; struct edge{int to,len,next;}e[M*10]; priority_queue <data> q; struct tree{int num;}t1[N*5],t2[N*5]; bool vis[M]; void addedge(int u,int v,int len) { e[++cnt].to=v;e[cnt].len=len;e[cnt].next=last[u];last[u]=cnt; } void build1(int d,int l,int r) { t1[d].num=++sz; if (l==r) { pos[l]=sz; return; } int mid=(l+r)/2; build1(d*2,l,mid);build1(d*2+1,mid+1,r); addedge(t1[d*2].num,t1[d].num,0);addedge(t1[d*2+1].num,t1[d].num,0); } void build2(int d,int l,int r) { t2[d].num=++sz;addedge(t2[d].num,t1[d].num,0); if (l==r) return; int mid=(l+r)/2; build2(d*2,l,mid);build2(d*2+1,mid+1,r); addedge(t2[d].num,t2[d*2].num,0);addedge(t2[d].num,t2[d*2+1].num,0); } void ins1(int d,int l,int r,int x,int y,int now) { if (x>y) return; if (l==x&&r==y) { addedge(t1[d].num,now,1); return; } int mid=(l+r)/2; ins1(d*2,l,mid,x,min(mid,y),now); ins1(d*2+1,mid+1,r,max(mid+1,x),y,now); } void ins2(int d,int l,int r,int x,int y,int now) { if (x>y) return; if (l==x&&r==y) { addedge(now,t2[d].num,1); return; } int mid=(l+r)/2; ins2(d*2,l,mid,x,min(y,mid),now); ins2(d*2+1,mid+1,r,max(x,mid+1),y,now); } void dij() { for (int i=1;i<=sz;i++) dis[i]=inf; dis[pos[p]]=0; data u;u.num=pos[p];u.val=0; q.push(u); for (int j=1;j<=sz;j++) { if (q.empty()) break; data u=q.top(); q.pop(); while (!q.empty()&&vis[u.num]) u=q.top(),q.pop(); if (vis[u.num]) break; int x=u.num;vis[x]=1; for (int i=last[x];i;i=e[i].next) if (!vis[e[i].to]&&dis[x]+e[i].len<dis[e[i].to]) { dis[e[i].to]=dis[x]+e[i].len; u.num=e[i].to;u.val=dis[e[i].to]; q.push(u); } } } int main() { scanf("%d%d%d",&n,&m,&p); build1(1,1,n);build2(1,1,n); for (int i=1;i<=m;i++) { int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); sz++; ins1(1,1,n,x1,y1,sz);ins2(1,1,n,x2,y2,sz); sz++; ins1(1,1,n,x2,y2,sz);ins2(1,1,n,x1,y1,sz); } dij(); for (int i=1;i<=n;i++) printf("%d\n",dis[pos[i]]/2); return 0; }
相关文章推荐
- bzoj 3073: [Pa2011]Journeys -- 线段树优化最短路
- BZOJ 3073: [Pa2011]Journeys 线段树优化最短路
- [bzoj3073][Pa2011]Journeys 线段树优化建边的最短路
- [线段树建图 bfs] BZOJ 3073 [Pa2011]Journeys
- BZOJ 3073 [Pa2011]Journeys 最短路 线段树优化建图
- 【线段树优化建图+最短路】BZOJ3073 [Pa2011]Journeys
- BZOJ_3073_[Pa2011]Journeys_线段树优化建图+BFS
- 【PA2011】【BZOJ3073】Journeys
- BZOJ[3073][Pa2011]Journeys 线段树优化建图+Dijkstra堆优化
- 【BZOJ3073】[Pa2011]Journeys 线段树+堆优化Dijkstra
- bzoj 3073: [Pa2011]Journeys
- 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra
- 3073: [Pa2011]Journeys|线段树|BFS
- 【PA2011】【BZOJ3069】Hard Choice 艰难的选择
- BZOJ3073 [Pa2011]Journeys
- BZOJ3490 : Pa2011 Laser Pool
- 【BZOJ】4130: [PA2011]Kangaroos【KD树——最长连续1的子段长度】
- BZOJ3073 : [Pa2011]Journeys
- BZOJ3070 : [Pa2011]Prime prime power 质数的质数次方
- 【线段树优化建图+BFS】BZOJ3073(Pa2011)[Journeys]题解