CF786B Legacy

CF786B Legacy

题意:
给定\(n\)个点
一共有\(m\)个连边,边有三种。
1.从\(u_i\)\(v_i\)的一条长度为\(w_i\)的边。
2.从\(u_i\)\([l,r]\)的一条长度为\(w_i\)的边。
3.从\([l,r]\)\(v_i\)的一条长度为\(w_i\)的边。

问从\(s\)到每一个点的最短路。
\(n,m<=10^5\)


很有意思的题目

显然不可以暴力连边,我们可以拿线段树的思想,让线段树的一个区间代表一个点。

拿两颗线段树分别维护区间连点和点连区间

以点连区间为例,直接拿点连树1的区间。而树1上面的边可以以费用0走到孩子节点。

对应区间连点,就是那树2的区间直接连点。而树2上面的边可以以费用0走到父亲节点。

连接树1树2就行了


Code:

#include <cstdio>
#include <cstring>
#include <queue>
#define ls ch[now][0]
#define rs ch[now][1]
#define ll long long
using namespace std;
const int N=100010;
const ll inf=0x3f3f3f3f3f3f3f3f;
int head[N<<3],to[N<<4],Next[N<<4],cnt;
int n,m,s,ch[N<<3][2],tot,typ;
ll edge[N<<4];
void add(int u,int v,ll w)
{
    edge[++cnt]=w;to[cnt]=v;Next[cnt]=head[u];head[u]=cnt;
}
int build1(int l,int r)
{
    if(l==r) return l;
    int now=++tot;
    int mid=l+r>>1;
    ls=build1(l,mid);
    rs=build1(mid+1,r);
    add(now,ls,0);
    add(now,rs,0);
    return now;
}
int build2(int id,int l,int r)
{
    if(l==r) return l;
    int now=++tot;
    int mid=l+r>>1;
    ls=build2(ch[id][0],l,mid);
    rs=build2(ch[id][1],mid+1,r);
    add(ls,now,0);
    add(rs,now,0);
    add(id,now,0);
    return now;
}
void connect(int now,int l,int r,int L,int R,int pos,ll w)
{
    if(l==L&&r==R)
    {
        if(typ==1)  add(pos,now,w);
        else add(now,pos,w);
        return;
    }
    int mid=L+R>>1;
    if(r<=mid)
        connect(ls,l,r,L,mid,pos,w);
    else if(l>mid)
        connect(rs,l,r,mid+1,R,pos,w);
    else
        connect(ls,l,mid,L,mid,pos,w),connect(rs,mid+1,r,mid+1,R,pos,w);
}
int root[2];
void init()
{
    scanf("%d%d%d",&n,&m,&s);
    tot=n;
    root[0]=build1(1,n);
    root[1]=build2(root[0],1,n);
    int opt,u,v,l,r;ll w;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d%d%lld",&u,&v,&w);
            add(u,v,w);
        }
        else if(opt==2)
        {
            scanf("%d%d%d%lld",&u,&l,&r,&w);//点连区间
            typ=1;
            connect(root[0],l,r,1,n,u,w);
        }
        else
        {
            scanf("%d%d%d%lld",&v,&l,&r,&w);
            typ=0;
            connect(root[1],l,r,1,n,v,w);
        }
    }
}
queue <int> q;
ll dis[N<<3];
int used[N<<3];
void work()
{
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        used[u]=0;
        q.pop();
        for(int i=head[u];i;i=Next[i])
        {
            int v=to[i];
            ll w=edge[i];
            if(dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                if(!used[v])
                {
                    used[v]=1;
                    q.push(v);
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(dis[i]==inf)
            printf("-1 ");
        else
            printf("%lld ",dis[i]);
    }
}
int main()
{
    init();
    work();
    return 0;
}


2018.7.20

posted @ 2018-07-20 16:21  露迭月  阅读(1196)  评论(0编辑  收藏  举报