zoukankan      html  css  js  c++  java
  • Codeforces Round #406 (Div. 2) 787-D. Legacy


    Rick and his co-workers have made a new radioactive formula and a lot of bad guys are after them. So Rick wants to give his legacy to Morty before bad guys catch them.

    There are n planets in their universe numbered from 1 to n. Rick is in planet number s (the earth) and he doesn't know where Morty is. As we all know, Rick owns a portal gun. With this gun he can open one-way portal from a planet he is in to any other planet (including that planet). But there are limits on this gun because he's still using its free trial.

    By default he can not open any portal by this gun. There are q plans in the website that sells these guns. Every time you purchase a plan you can only use it once but you can purchase it again if you want to use it more.

    Plans on the website have three types:

    1. With a plan of this type you can open a portal from planet v to planet u.
    2. With a plan of this type you can open a portal from planet v to any planet with index in range [l, r].
    3. With a plan of this type you can open a portal from any planet with index in range [l, r] to planet v.

    Rick doesn't known where Morty is, but Unity is going to inform him and he wants to be prepared for when he finds and start his journey immediately. So for each planet (including earth itself) he wants to know the minimum amount of money he needs to get from earth to that planet.

    Input

    The first line of input contains three integers nq and s (1 ≤ n, q ≤ 105, 1 ≤ s ≤ n) — number of planets, number of plans and index of earth respectively.

    The next q lines contain the plans. Each line starts with a number t, type of that plan (1 ≤ t ≤ 3). If t = 1 then it is followed by three integers vu and w where w is the cost of that plan (1 ≤ v, u ≤ n1 ≤ w ≤ 109). Otherwise it is followed by four integers vlr and wwhere w is the cost of that plan (1 ≤ v ≤ n1 ≤ l ≤ r ≤ n1 ≤ w ≤ 109).

    Output

    In the first and only line of output print n integers separated by spaces. i-th of them should be minimum money to get from earth to i-th planet, or  - 1 if it's impossible to get to that planet.

    Examples
    input
    Copy
    3 5 1
    2 3 2 3 17
    2 3 2 2 16
    2 2 2 3 3
    3 3 1 1 12
    1 3 3 17
    output
    Copy
    0 28 12 
    input
    Copy
    4 3 1
    3 4 1 3 12
    2 2 3 4 10
    1 2 4 16
    output
    Copy
    0 -1 -1 12 
    Note

    In the first sample testcase, Rick can purchase 4th plan once and then 2nd plan in order to get to get to planet number 2.

    建立两棵线段树,对树上结点进行建边;注意点是图的点数要开8倍,INF要开大。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <set>
    #include <map>
    //#define INF 0x3f3f3f3f
    #define ll long long
    #define ull unsigned long long
    #define lowbit(x) (x&(-x))
    #define eps 0.00000001
    #define PI acos(-1)
    #define pn printf("
    ");
    using namespace std;
    
    int n,q,s;
    const int maxn = 1e5+5;
    const int MAXN = maxn << 3;
    const ll INF = 1e18+1;
    int tol; // 单树结点数
    int up[maxn << 2], dn[maxn << 2]; // 上面的树的编号, 下面的树的编号
    int u, op;
    int u_id[maxn]; // 下标为i的点在线段树中的编号
    ll w;
    
    struct qnode
    {
        int v;
        ll c;
        qnode(int _v=0,ll _c=0):v(_v),c(_c){}
        bool operator <(const qnode &r) const
        {
            return c > r.c;
        }
    };
    struct Edge {
        int v;
        ll cost;
        Edge(int _v=0,ll _cost=0):v(_v),cost(_cost){}
    };
    vector<Edge>E[MAXN];
    bool vis[MAXN];
    ll dist[MAXN];
    
    void init()
    {
        tol = 0;
        memset(up, 0, sizeof up);
        memset(dn, 0, sizeof dn);
        for(int i=0;i<MAXN;i++) E[i].clear();
        tol = n*4-1;
    }
    
    void Dijkstra(int n,int start)//点的编号从1开始
    {
        memset(vis, false, sizeof(vis));
        for(int i=1; i<=n; i++)
            dist[i] = INF;
        priority_queue <qnode> que;
        while(!que.empty()) que.pop();
        dist[start] = 0;
        que.push(qnode(start, 0));
        qnode tmp;
        while(!que.empty())
        {
            tmp = que.top();
            que.pop();
            int u = tmp.v;
            if(vis[u]) continue;
            vis[u] = true;
            for(int i=0; i<E[u].size(); i++)
            {
                int v = E[tmp.v][i].v;
                ll cost = E[u][i].cost;
                if(!vis[v] && dist[v] > dist[u]+cost)
                {
                    dist[v] = dist[u]+cost;
                    que.push(qnode(v,dist[v]));
                }
            }
        }
    }
    
    void addedge(int u, int v, ll w)
    {
        E[u].push_back(Edge(v,w));
        
        //cout << u << " -> " << v << " : " << w << endl;
    }
    
    void build(int i,int b,int e,int pos, int *t)
    {
        if(b == e)
        {
            t[i] = i;
            u_id[pos] = i;
            return ;
        }
        
        int mid = (b + e) / 2;
        if(pos <= mid) build(i << 1, b, mid, pos, t);
        else build(i << 1 | 1, mid + 1, e, pos, t);
        
        t[i] = i;
    }
    
    void update(int i, int b, int e, int l, int r, bool mode)// mode=0: 点到区间,  1: 区间到点
    {
        if(b >= l && e <= r)
        {
            if(mode)
            {
                addedge(up[i], u_id[u]+tol, w); // 上面的树的区间的编号 到 下面的树的点的编号 建边
            }
            else
            {
                addedge(u_id[u], dn[i], w); // 上面的树的点的编号 到 下面的树的区间的编号 建边
            }
            return ;
        }
        
        int mid = (b + e) >> 1;
        if(r <= mid) update(i << 1, b, mid, l, r, mode);
        else if(l > mid) update(i << 1 | 1, mid+1, e, l, r, mode);
        else
        {
            update(i << 1, b, mid, l, r, mode);
            update(i << 1 | 1, mid+1, e, l, r, mode);
        }
    }
    
    void build_edge()
    {
        int vis[MAXN] = {0};
        queue <int> que;
        for(int i=1;i<=n;i++)
        {
            que.push(u_id[i]);
            addedge(u_id[i], u_id[i] + tol, 0);
            addedge(u_id[i] + tol, u_id[i], 0); // 点到点建双向边
        }
        while(!que.empty())
        {
            int u = que.front();
            que.pop();
            
            addedge(u, u >> 1, 0); // 从下到上建单向边
            addedge( (u>>1) + tol, u+tol, 0); // 从上到下建单向边
            if( (u>>1) > 1 && !vis[u>>1] )
            {
                vis[u>>1] = 1;
                que.push( u>>1 ); // 结点上移
            }
        }
    }
    
    int main()
    {
        while(~scanf("%d%d%d", &n,&q,&s))
        {
            init();
            int l, r;
            for(int i=1;i<=n;i++)
                build(1, 1, n, i, up);  // 对上面的树的节点赋值
            for(int i=1;i<=tol;i++)
                dn[i] = up[i] + tol;    // 下面的树的节点的值 赋为 上面的树对应的点+tol
            build_edge();   // 分别建从下到上、从上到下的单向边;点对点的双向边
            
            while(q--)
            {
                scanf("%d", &op);
                if(op == 1) // 点到点建边
                {
                    int v;
                    scanf("%d%d%lld", &u, &v, &w);
                    addedge(u_id[u], u_id[v]+tol, w); // 从上面的树的叶子结点指到下面树叶子结点
                }
                else if(op == 2) // 点到区间
                {
                    scanf("%d%d%d%lld", &u, &l, &r, &w);
                    update(1, 1, n, l, r, 0);
                }
                else // 区间到点
                {
                    scanf("%d%d%d%lld", &u, &l, &r, &w);
                    update(1, 1, n, l, r, 1);
                }
            }
           
            Dijkstra(tol<<1, u_id[s]); // 总点数:两个线段树的节点数*2, 起点:下标为s的点在上面的树中的编号
            for(int i=1;i<=n;i++)
            {
                if(i > 1) printf(" ");
                printf("%lld", dist[u_id[i] + tol] == INF ? -1 : dist[u_id[i] + tol] );
            } pn;
        }
    }
  • 相关阅读:
    composer 中国全量镜像 laravel-china.org
    Increase PHP script execution time with Nginx
    How to make a USB stick use ISO image file in debian
    Getting svn to ignore files and directories
    Carbon document
    Use Laravel/homestead 环境维护基于 brophp 开发的老项目
    Vagrant WinNFSd
    How to use jQuery countdown plugin
    消息系统的设计与实现
    VMvare 复制的数据库,需要改变的配置
  • 原文地址:https://www.cnblogs.com/HazelNut/p/10301524.html
Copyright © 2011-2022 走看看