CF786B Legacy
### 线段树优化建图
Luogu链接
裸题,区间连点,点连区间
假如直接连边跑的话一定会T
这时候就需要线段树优化建图了
两个线段树
一个树是区间连点的,叫out
一个树是点连区间的,叫in
但是两个树内部连边的方向不一样
如图
假如相反必然就不对了包含关系错了
剩下的就好写了
代码如下:
#include<bits/stdc++.h> #define mk make_pair #define int long long using namespace std; const int maxn=1e5+10,inf=0x3f3f3f3f3f3f3f3f; int n,q,st,cnt,trin[maxn<<2],trot[maxn<<2]; vector<pair<int,int> > G[maxn*10]; void build(int p,int l,int r){ if(l==r){ trin[p]=l;trot[p]=r;return; } int mid=(l+r)>>1; build(p<<1,l,mid);build(p<<1|1,mid+1,r); trin[p]=++cnt;trot[p]=++cnt; G[trot[p<<1]].push_back(mk(trot[p],0)); G[trot[p<<1|1]].push_back(mk(trot[p],0)); G[trin[p]].push_back(mk(trin[p<<1],0)); G[trin[p]].push_back(mk(trin[p<<1|1],0)); } void upin(int p,int l,int r,int x,int y,int from,int cs){ if(x<=l && r<=y){ G[from].push_back(mk(trin[p],cs));return; } int mid=(l+r)>>1; if(x<=mid) upin(p<<1,l,mid,x,y,from,cs); if(y>mid) upin(p<<1|1,mid+1,r,x,y,from,cs); } void upot(int p,int l,int r,int x,int y,int to,int cs){ if(x<=l && r<=y){ G[trot[p]].push_back(mk(to,cs));return; } int mid=(l+r)>>1; if(x<=mid) upot(p<<1,l,mid,x,y,to,cs); if(y>mid) upot(p<<1|1,mid+1,r,x,y,to,cs); } int dis[maxn*10],inq[maxn*10]; inline void spfa(){ memset(dis,0x3f,sizeof(dis));memset(inq,0,sizeof(inq)); queue<int> q;q.push(st);dis[st]=0;inq[st]=1; while(q.size()){ int x=q.front();q.pop();inq[x]=0; for(unsigned int i=0;i<G[x].size();i++){ int y=G[x][i].first,z=G[x][i].second; if(dis[y]>dis[x]+z){ dis[y]=dis[x]+z; if(!inq[y]){ inq[y]=1;q.push(y); } } } } } signed main() { scanf("%lld%lld%lld",&n,&q,&st); cnt=n; build(1,1,n); for(int op,i=1;i<=q;i++){ scanf("%d",&op); if(op==1){ int f,t,w;scanf("%lld%lld%lld",&f,&t,&w);G[f].push_back(mk(t,w)); } if(op==2){ int f,l,r,w;scanf("%lld%lld%lld%lld",&f,&l,&r,&w); upin(1,1,n,l,r,f,w); } if(op==3){ int t,l,r,w;scanf("%lld%lld%lld%lld",&t,&l,&r,&w); upot(1,1,n,l,r,t,w); } } spfa(); for(int i=1;i<=n;i++){ if(dis[i]<inf) printf("%lld ",dis[i]); else printf("-1 "); } return 0; }