CF786B Legacy 线段树优化建图

北城余情 提交于 2019-12-01 13:16:01

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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!