萌新求调线段树优化建图

P6348 [PA2011] Journeys

luoyx @ 2023-05-04 19:00:47

#include <bits/stdc++.h>
using namespace std;
int n,m,s;
int a,b,c,d;
const int N=3e6+5;
int head[N],ecnt;
struct edge{
    int v,nxt,w;    
}e[N];
void add(int u,int v,int w){
    e[ecnt].v=v;
    e[ecnt].w=w;
    e[ecnt].nxt=head[u];
    head[u]=ecnt++;
}

int lc[N],rc[N];
int cnt;
int rt,rt2;
void build(int &p,int l,int r){
    if(l==r){
        p=l;
        return ;
    }
    p=++cnt;
    int m=l+r>>1;
    build(lc[p],l,m);
    build(rc[p],m+1,r);
    add(p,lc[p],0); add(p,rc[p],0);
} 
void build2(int &p,int l,int r){
    if(l==r){
        p=l;
        return ;
    }
    p=++cnt;
    int m=l+r>>1;
    build2(lc[p],l,m);
    build2(rc[p],m+1,r);
    add(lc[p],p,0); add(rc[p],p,0);
}

void upd(int p,int l,int r,int q,int L,int R,int op){
    if(L<=l&&r<=R){
        if(op==1) add(p,q,0);
        else add(q,p,0);
        return ;
    }
    int m=l+r>>1;
    if(L<=m) upd(lc[p],l,m,q,L,R,op);
    if(R>=m+1) upd(rc[p],m+1,r,q,L,R,op);
}
void add_edge(int a,int b,int c,int d){
    int q=++cnt,q2=++cnt;
    upd(rt,1,n,q,a,b,1);
    upd(rt2,1,n,q2,c,d,2);
    add(q,q2,1);
}

int dis[N];
void spfa(int s){
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;
    queue<int> q;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];i+1;i=e[i].nxt){
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].w){
                dis[v]=dis[u]+e[i].w;
                q.push(v);
            }
        }
    }
}
int main(){
    cin>>n>>m>>s;
    memset(head,-1,sizeof(head));
    cnt=n;
    build(rt,1,n); build2(rt2,1,n);
    for(int i=1;i<=m;i++){
        cin>>a>>b>>c>>d;
        add_edge(a,b,c,d);
        add_edge(c,d,a,b);
    } 
    spfa(s);
    for(int i=1;i<=n;i++){
        cout<<dis[i]<<endl;
    }
}

by hy233 @ 2023-05-04 19:07:42

@luoyx 两棵线段树边的方向反了,且两棵树的叶子之间要连边(也有可能是不同连法?


by luoyx @ 2023-05-04 19:55:57

@hy233 我的程序中两颗线段树的叶子节点编号相同,边的方向反了是指 build 吗?


by hy233 @ 2023-05-04 20:06:46

@luoyx 应该是的,大概想法就是你从叶子节点出发往上(tree1 up),通过某个区间跨到另一个线段树上,再走回叶子节点(tree2 down),这样形成走一步。


by luoyx @ 2023-05-04 20:14:37

@hy233 拜谢大佬,已A


|