Codeforces-786B-Legacy (线段树+最短路)

看到区间很容易就能想到线段树。 
对于操作2,我们可以建立一棵线段树,线段树的某一个结点表示区间 [l,r] ,那么在图中建立一个结点 u 表示区间 [l,r] ,新建点u 指向 l,l+1,l+2...r的边,权值为 0 。 
当得到一个操作 (v,l,r,w) 时,查询一次线段树,把所有符合 [ql,qr]∈[l,r] 的极大区间结点建立一条被 v 指向的边,权值为 w 。这样就能表示 v指向 [l,r] 了。 
每一次新建边的操作复杂度是 O(2logn) , 
对于操作3,与操作2类似。得建立两颗线段树来转化,因为区间和对应点列的上下更新是不兼容的,向上是维护最大,向下是维护相同真实值

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>

using namespace std;

int n,q,s;
long long inf=1e18;
long long dis[100005*10];

struct node
{
    int u,v;
    long long w;
    node(int uu,int vv,long long ww)
    {
        u=uu;
        v=vv;
        w=ww;
    }

    bool friend operator<(node x,node y)
    {
        return x.w>y.w;
    }
};

vector<node>e[100005*10];

int trd1[100005*4];
int trd2[100005*4];

int cnt;

void build1(int i,int l,int r)
{
    if(trd1[i]==0)
        trd1[i]=++cnt;
    for(int j=l;j<=r;j++)
    {
        e[j].push_back(node(j,trd1[i],0));
    }
    if(l==r)
        return ;
    else
    {
        int mid=(l+r)/2;
        build1(i*2,l,mid);
        build1(i*2+1,mid+1,r);
    }
}

void build2(int i,int l,int r)
{
    if(trd2[i]==0)
        trd2[i]=++cnt;
    for(int j=l;j<=r;j++)
    {
        e[trd2[i]].push_back(node(trd2[i],j,0));
    }
    if(l==r)
        return;
    else
    {
        int mid=(l+r)/2;
        build2(i*2,l,mid);
        build2(i*2+1,mid+1,r);
    }
}

void update2(int i,int l,int r,int ql,int qr,int u,long long w)
{
    if(l==ql && r==qr)
    {
        e[u].push_back(node(u,trd2[i],w));
    }
    else
    {
        int mid=(l+r)/2;
        if(mid>=qr)
        {
            update2(i*2,l,mid,ql,qr,u,w);
        }
        else if(mid<ql)
        {
            update2(i*2+1,mid+1,r,ql,qr,u,w);
        }
        else
        {
            update2(i*2,l,mid,ql,mid,u,w);
            update2(i*2+1,mid+1,r,mid+1,qr,u,w);
        }
    }
}

void update1(int i,int l,int r,int ql,int qr,int u,long long w)
{
    if(l==ql && r==qr)
    {
        e[trd1[i]].push_back(node(trd1[i],u,w));
    }
    else
    {
        int mid=(l+r)/2;
        if(mid>=qr)
        {
            update1(i*2,l,mid,ql,qr,u,w);
        }
        else if(mid<ql)
        {
            update1(i*2+1,mid+1,r,ql,qr,u,w);
        }
        else
        {
            update1(i*2,l,mid,ql,mid,u,w);
            update1(i*2+1,mid+1,r,mid+1,qr,u,w);
        }
    }
}

int main()
{
    while(~scanf("%d%d%d",&n,&q,&s))
    {
        cnt=n;
        memset(trd1,0,sizeof(trd1));
        memset(trd2,0,sizeof(trd2));

        for(int i=0;i<100000*10;i++)
            dis[i]=inf,e[i].clear();

        build1(1,1,n);
        build2(1,1,n);

        while(q--)
        {
            int f;
            scanf("%d",&f);
            if(f==1)
            {
                int u,v;
                long long w;
                scanf("%d%d%lld",&u,&v,&w);
                e[u].push_back(node(u,v,w));
            }
            else if(f==2)
            {
                int u,l,r;
                long long w;
                scanf("%d%d%d%lld",&u,&l,&r,&w);
                update2(1,1,n,l,r,u,w);
            }
            else if(f==3)
            {
                int u,l,r;
                long long w;
                scanf("%d%d%d%lld",&u,&l,&r,&w);
                update1(1,1,n,l,r,u,w);
            }
        }
        //dijistra
        dis[s]=0;
        priority_queue<node> pq;
        pq.push(node(s,0,0));
        while(!pq.empty())
        {
            node cur=pq.top();
            pq.pop();
            int tu=cur.u;
            int len=e[tu].size();
            //cout<<len<<endl;
            for(int i=0;i<len;i++)
            {
                int v=e[tu][i].v;
                long long tw=e[tu][i].w;

                if(dis[v]>dis[tu]+tw)
                {
                    dis[v]=dis[tu]+tw;
                    pq.push(node(v,0,dis[v]));
                }
            }
        }

        for(int i=1;i<=n;i++)
        {
            if(dis[i]==inf)
            {
                printf("-1 ");
            }
            else
            {
                printf("%lld ",dis[i]);
            }
        }
        printf("\n");
    }
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值