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;
}