CF786B Legacy(线段树优化建图+最短路)

在qbxt某营集体做的

题解里以及外地OIer基本上都写两颗线段树的

而我们六安的OIer神TM思维一致——只用一颗线段树,类似于一维分层图的思想,第二层上与第一层相对应的结点的编号是第一层结点编号+NUM,而且貌似比分颗的思维正常一点,因为满足lson=k<<1,rson=k<<1|1,和一般的线段树相似度高。

至于为什么要分颗或分层,容易想明白树边(辅助边)必须是双向的(因为要用祖先结点的出入信息),但如果不分颗或分层的话求出来最短路不很明显是0了吗QwQ

所以分层的话父向子应是一层,子向父应在另一层,两层之间通过叶节点相连

另外关于叶结点的处理问题,YoOXiii和Pride205是把原图第i结点投影到树上第i+n结点(n为原图结点个数)

这个详见他们的代码(其实我也没仔细研究清楚他们的处理方法),这里不偷了(偷窃犯罪w),要看自己找

由于我和他们不坐一块,想思路时没有交流,所以我没有这样写,我是把第一层按照一般线段树的编号建,这样容易一点。然后把原图结点直接向叶子结点映射即可(开一个pos数组)(才知道szsz46也是这么写的,原来六安OIer的思维同步性不随空间改变QwQ)

然后......

上代码吧

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#define NUM 1000000
#define maxn 100005<<5
//这两个范围要调好 
#define int long long
using namespace std;
typedef long long ll;

inline void input(ll &x){
    ll ans=0,f=1;
    char c=getchar();
    while(c>'9'||c<'0'){
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        ans=ans*10+c-48;
        c=getchar();
    }
    x=ans*f;
}

inline void output(ll x){
    if(x<0)x=-x,putchar('-');
    if(x>9)output(x/10);
    putchar(x%10+48);
}

inline void writeln(ll x){
    output(x);
    putchar('\n');
}

int n,m,s,head[maxn],c[maxn],pos[maxn],vis[maxn],dis[maxn],cnt;

//pos:题中结点在树上的编号 

struct edge{
    int v,w,next;
}e[maxn];

struct node{
    int dis,u;
    bool operator<(const node &x)const{return x.dis<dis;}
};

inline void add(int u,int v,int w){
    e[++cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt;
//  cout<<u<<' '<<v<<' '<<w<<endl;
}

inline void build(int k,int l,int r){
    if(l==r){
        pos[l]=k;
        add(k+NUM,k,0);
        add(k,k+NUM,0);
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    add(k<<1,k,0);
    add(k<<1|1,k,0);
    add(k+NUM,(k<<1)+NUM,0);//调了一个小时:加括号;在括号外加NUM而不是给k加NUM 
    add(k+NUM,(k<<1|1)+NUM,0);
}

inline void add(int k,int l,int r,int xl,int xr,int from,int w,int opt){
    if(xl<=l&&r<=xr){
        if(opt==2)add(from,k+NUM,w);
        else if(opt==3)add(k,from,w);
        return;
    }
    int mid=(l+r)>>1;
    if(xl<=mid)add(k<<1,l,mid,xl,xr,from,w,opt);
    if(xr>=mid+1)add(k<<1|1,mid+1,r,xl,xr,from,w,opt);
}

priority_queue<node> q;

inline void dijkstra(){
    s=pos[s];
    q.push((node){0,s});
    dis[s]=0;
    while(!q.empty()){
        int x=q.top().u;
        q.pop();
        if(vis[x])continue;
        vis[x]=1;
        for(int i=head[x];i!=-1;i=e[i].next){
            int y=e[i].v;
            if(!vis[y]&&dis[y]>dis[x]+e[i].w){
                dis[y]=dis[x]+e[i].w;
                q.push((node){dis[y],y});//想不到吧,这一行打错使我调了半个小时 
            }
        }
    }
    s<<=1;
    if(s>=1)dijkstra();
}

signed main(){
    memset(head,-1,sizeof(head));
    memset(dis,127,sizeof(dis));
    memset(vis,0,sizeof(vis));
    input(n);input(m);input(s);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        int opt;
        input(opt);
        if(opt==1){
            int u,v,w;
            input(u);input(v);input(w);
            add(pos[u],pos[v],w);
        }
        else if(opt==2){
            int u,l,r,w;
            input(u);input(l);input(r);input(w);
            add(1,1,n,l,r,pos[u],w,opt);
        }
        else if(opt==3){
            int u,l,r,w;
            input(u);input(l);input(r);input(w);
            add(1,1,n,l,r,pos[u],w,opt);
        }
    }
    dijkstra();
//  for(int i=1;i<=4*n;i++)cout<<i<<' '<<dis[i]<<endl;
    for(int i=1;i<=n;i++)output(dis[pos[i]]<=1e15?dis[pos[i]]:-1),putchar(' ');
}
上一篇:模拟实现strncpy,strncat,strncmp


下一篇:[CF786B]Legacy