洛谷传送门
线段树优化建图
用两个线段树A和B,一个我们称之为入树,一个我们称之为出树,对于每一条边,都是从入树连向出树,具体如下:
- 若是两个点之间连边,直接从入树对应的叶子节点连向出树的叶子节点
- 若为单点连向区间,则入树的叶子节点连向出树的区间(按照线段树的插入)
- 若为区间连向单点,同理,入树的区间连向出树的叶子节点
然后就可以在线段树上做各种图论算法了(把两个线段树看做图即可)。
解题思路
很显然是个板子,线段树优化完建图后,直接跑最短路即可。
AC代码
#include<cstdio> #include<iostream> #include<cstring> #include<iomanip> #include<cmath> #include<set> using namespace std; const int maxn=400005; const long long maxx=10000000000005; int n,m,s,qaq=400001,p[maxn*2],cnt; long long dis[maxn*2]; set<pair<long long,int> > q; struct node{ int v,next,w; }e[maxn*5]; int find(int x){ int l=1,r=n,id=1; while(l!=r){ int mid=(l+r)/2; if(x<=mid) r=mid,id=id*2; else l=mid+1,id=id*2+1; } return id; } void insert(int u,int v,int w){ cnt++; e[cnt].v=v; e[cnt].next=p[u]; e[cnt].w=w; p[u]=cnt; } void update(int k,int id,int l,int r,int x,int y,int z,int w){ if(l>=x&&r<=y){ if(k==1) insert(z,qaq+id,w); if(k==2) insert(id,z,w); if(k==3) insert(z,qaq+id,w); return; } int mid=(l+r)/2; if(x<=mid) update(k,id*2,l,mid,x,y,z,w); if(y>mid) update(k,id*2+1,mid+1,r,x,y,z,w); } void add(int ux,int uy,int vx,int vy,int w){ if(vx!=vy){ int u=find(ux); update(1,1,1,n,vx,vy,u,w); return; } if(ux!=uy){ int v=find(vx); update(2,1,1,n,ux,uy,qaq+v,w); return; } int u=find(ux); update(3,1,1,n,vx,vx,u,w); } void init(int id,int l,int r){ if(l==r){ insert(qaq+id,id,0); return; } int mid=(l+r)/2; insert(id*2,id,0); insert(id*2+1,id,0); insert(qaq+id,qaq+id*2,0); insert(qaq+id,qaq+id*2+1,0); init(id*2,l,mid); init(id*2+1,mid+1,r); } int main(){ memset(p,-1,sizeof(p)); cin>>n>>m>>s; for(int i=1;i<maxn*2;i++) dis[i]=maxx; init(1,1,n); for(int i=1;i<=m;i++){ int t; scanf("%d",&t); if(t==1){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,u,v,v,w); }else { if(t==2){ int u,l,r,w; scanf("%d%d%d%d",&u,&l,&r,&w); add(u,u,l,r,w); }else{ int l,r,v,w; scanf("%d%d%d%d",&v,&l,&r,&w); add(l,r,v,v,w); } } } int f=find(s); dis[f]=0; q.insert(make_pair(0,f)); while(!q.empty()){ int u=q.begin()->second; q.erase(q.begin()); for(int i=p[u];i!=-1;i=e[i].next){ int v=e[i].v; if(dis[v]>dis[u]+e[i].w){ q.erase(make_pair(dis[v],v)); dis[v]=dis[u]+e[i].w; q.insert(make_pair(dis[v],v)); } } } for(int i=1;i<=n;i++) { int ff=find(i); cout<<((dis[ff]!=maxx)?dis[ff]:-1)<<" "; } return 0; }