CF786B Legacy

https://www.luogu.com.cn/problem/CF786B

线段树优化建图

对于区间\([l,r]\),可以用线段树中的节点优化建图

对于从外面指向指定区间的边,它只能往下转移

例:

如果存在\(v\rightarrow [l,r]\),那么一定存在\(v\rightarrow [s,t]([s,t] \in [l,r])\)

因此需要边\([l,r]\rightarrow [s,t]\)才能实现转移

对于从指定区间指向外面的边,它只能往上转移

例:

如果\([l,r]\rightarrow v\),那么一定存在\([s,t]\rightarrow v ([s,t] \in[l,r])\)

因此需要边\([s,t]\rightarrow [l,r]\)才能实现转移

因为两种不同的情况需要两种类型的附加图,所以我们需要两颗线段树维护

然后跑最短路就好了

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#define N 100005
#define ll long long
#define pr pair<ll,int>
#define mp make_pair
#define INF 123456789987654321
using namespace std;
int cnt,t;
priority_queue<pr,vector<pr>,greater<pr> >q;
struct edge
{
    int v,cost;
    edge (int xx=0,int yy=0)
    {
        v=xx,cost=yy;
    }
};
vector<edge>e[N << 3];
int n,Q,s,rt1,rt2,opt,v,u,l,r,ls[N << 2],rs[N << 2];
ll w;
ll dis[N << 2];
bool vis[N << 2];
void add(int x,int y,int z)
{
    e[x].push_back(edge(y,z));
}
void build(int &p,int l,int r)
{
    if (l==r)
    {
        p=l;
        return;
    }
    p=++cnt;
    int mid=(l+r) >> 1;
    build(ls[p],l,mid);
    build(rs[p],mid+1,r);
    add(p,ls[p],0),add(p,rs[p],0);
}
void build_2(int &p,int l,int r)
{
    if (l==r)
    {
        p=l;
        return;
    }
    p=++cnt;
    int mid=(l+r) >> 1;
    build_2(ls[p],l,mid);
    build_2(rs[p],mid+1,r);
    add(ls[p],p,0),add(rs[p],p,0);
}
void change(int p,int l,int r,int x,int y)
{
    if (l>y||r<x)
        return;
    if (x<=l&&r<=y)
    {
        add(v,p,w);
        return;
    }
    int mid=(l+r) >> 1;
    change(ls[p],l,mid,x,y);
    change(rs[p],mid+1,r,x,y);
}
void change_2(int p,int l,int r,int x,int y)
{
    if (l>y||r<x)
        return;
    if (x<=l&&r<=y)
    {
        add(p,v,w);
        return;
    }
    int mid=(l+r) >> 1;
    change_2(ls[p],l,mid,x,y);
    change_2(rs[p],mid+1,r,x,y);
}
int main()
{
    scanf("%d%d%d",&n,&Q,&s);
    cnt=n;
    build(rt1,1,n);
    build_2(rt2,1,n);
    for (int i=1;i<=Q;i++)
    {
        scanf("%d",&opt);
        switch (opt)
        {
            case 1:
                scanf("%d%d%lld",&v,&u,&w);
                add(v,u,w);
                break;
            case 2:
                scanf("%d%d%d%lld",&v,&l,&r,&w);
                t=1;
                change(rt1,1,n,l,r);
                break;
            case 3:
                scanf("%d%d%d%lld",&v,&l,&r,&w);
                t=2;
                change_2(rt2,1,n,l,r);
                break;
        }
    }
    for (int i=1;i<=cnt;i++)
        dis[i]=INF,vis[i]=false;
    dis[s]=0;
    q.push(mp(0,s));
    while (!q.empty())
    {
        pr Ru=q.top();
        q.pop();
        #define u Ru.second
        if (vis[u])
            continue;
        vis[u]=true;
        for (vector<edge>::iterator it=e[u].begin();it!=e[u].end();++it)
        {
            if (dis[u]+it->cost<dis[it->v])
            {
                dis[it->v]=dis[u]+it->cost;
                q.push(mp(dis[it->v],it->v));
            }
        }
    }
    for (int i=1;i<=n;i++)
        printf("%lld ",(dis[i]!=INF)?dis[i]:(-1));
    putchar('\n');
    return 0;
}
posted @ 2020-07-30 17:34  GK0328  阅读(363)  评论(0编辑  收藏  举报