zoukankan      html  css  js  c++  java
  • 【题解】Hikari的幸福生活

    题目背景

    (Hikari)想在爬完风暴梯子之后去找(Tairitsu)玩。

    题目描述

    (Hikari)手里有一张里黑包的地图,从地图中我们可以知道,里黑包有(n)首歌曲,歌曲之间有(m)条有向带权道路。里黑包有
    两种歌曲,他们的名字很奇怪,一种叫你玩得来吗玩不来赶紧退,另一个叫前奏缓和中间变速尾杀飞天,由于名字太
    过长我们简称他们为A党和B党。对于同一首歌曲里的所有天地按键都支持同一个歌曲类型,我们把支持同一个类型的两个
    歌曲称为同流合污歌曲,支持不同的类型的两首歌曲叫做齐头并进歌曲。现在(Hikari)要规划她的旅游路线,为了使路线更加合理,他想知道对于每一个歌曲,离它最近的同流合污歌曲和齐头并进歌曲的距离分别是多少。

    输入格式

    第一行两个数字表示(n) , (m)
    接下来一行(n)个数字,第(i)个数字是(0)(1)表示第(i)个城市支持的是A党还是B党。
    接下来(m)行,每行三个数字(x),(y),(z),表示存在一条从(x)(y)的权值为(z)的单向边。

    样例输入

    6 12
    0 1 1 1 1 0
    2 4 0
    1 3 0
    1 6 3
    4 5 2
    3 4 6
    2 5 4
    4 3 9
    3 1 3
    2 5 5
    6 1 9
    1 2 7
    2 1 8

    样例输出

    3 0
    0 8
    6 3
    2 12
    -1 -1
    9 9

    样例解释

    自己跑一跑就出来了我就不解释了。

    数据范围

    为了方便选手写部分分,各个特殊性质的数据点中个位和十位均不相同,选手可据此来编写部分分代码。
    各边边权均为正数,保证int可存下

    测试数据点 n m 特殊性质 时间限制
    1 10 30 2s
    2 20 60 2s
    3 3000 15000 2s
    4 4000 20000 2s
    5 5000 25000 2s
    6 6000 30000 2s
    7 7000 35000 2s
    8 8000 40000 2s
    9 9000 45000 2s
    10 10000 50000 2s
    11 49911 300000 所有的城市都相互之间都是友好城市 2s
    12 49912 300000 所有城市构成一条单方向的链 2s
    13 49913 300000 所有城市构成一条单方向的链 2s
    14 49914 300000 所有城市构成一棵有父亲指向孩子的树 2s
    15 49915 300000 所有城市构成一棵有父亲指向孩子的树 2s
    16 49916 300000 所有城市构成一条单方向的环 2s
    17 49917 300000 所有城市构成一条单方向的环 2s
    18 49918 300000 5s
    19 49919 300000 5s
    20 50000 300000 5s

    注:对于所有数据保证不存在自环。

    #include<bits/stdc++.h>
        
    #define LL long long
        
    using namespace std;
        
    /*Grievous Lady*/
        
    template <typename T> void read(T & t){
        t = 0;int f = 1;char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-')f =- 1;ch = getchar();}
        do{t = (t << 1) + (t << 3) + ch - '0';ch = getchar();}while(ch >= '0' && ch <= '9');t *= f;
    }
    
    #define INF 0x7fffffff
    
    const int kato = 5e4 + 1;
    
    struct edge{
        int to , nxt , dis;
    }e[3000000 + 1];
    
    bool vis[kato];
    
    int cnt;
    
    int head[kato] , ans[kato][2];
    
    inline void add(int u , int to , int dis){
        cnt ++;
        e[cnt].to = to;
        e[cnt].dis = dis;
        e[cnt].nxt = head[u];
        head[u] = cnt;
    }
    
    int dis[kato];
    
    int n , m , a[kato] , tot[kato];
    
    queue<int> q;
    
    inline void SPFA(int t , int b , int s){
    	for(int i = 1;i <= n;i ++){
            dis[i] = INF;
            if(a[i] == t && tot[i] == b) q.push(i) , vis[i] = true , dis[i] = 0;
        }
        while(!q.empty()){
        	int u = q.front();
            q.pop();
            vis[u] = false;
            for(int i = head[u]; i ;i = e[i].nxt){
                if(dis[u] + e[i].dis < dis[e[i].to]){
                    dis[e[i].to] = dis[u] + e[i].dis;
                    if(!vis[e[i].to]){  
                        vis[e[i].to] = true, q.push(e[i].to);
                    }
                }
            }
        }
        for(int i = 1;i <= n;i ++){
            if(a[i] == s && tot[i] != b){
                if(ans[i][t ^ s] > dis[i]){
                    ans[i][t ^ s] = dis[i];
                }
            }
        }
    }
    
    inline void doit(){
        SPFA(0 , 0 , 0);SPFA(0 , 0 , 1);
        SPFA(0 , 1 , 0);SPFA(0 , 1 , 1);
        SPFA(1 , 0 , 0);SPFA(1 , 0 , 1);
        SPFA(1 , 1 , 0);SPFA(1 , 1 , 1);
    }
    
    inline int Ame_(){
        // freopen("map.in" , "r" , stdin);
        // freopen("map.out" , "w" , stdout);
        read(n);read(m);
        for(int i = 1;i <= n;i ++){
            read(a[i]);
            ans[i][0] = ans[i][1] = INF;
        }   
        int x , y , z;
        for(int i = 1;i <= m;i ++){
            read(x);read(y);read(z);
            add(y , x , z);
        }
        for(int i = 0;i <= 15;i ++){
            for(int j = 1;j <= n;j ++) {
                tot[j] = (j >> i) & 1;
            }
            doit();
        }
        for(int i = 1;i <= n;i ++){
            if(ans[i][0] == INF){
                printf("-1 ");
            }
            else{ 
                printf("%d " , ans[i][0]);
            }
            if(ans[i][1] == INF){
                printf("-1
    ");
            }
            else{
                printf("%d
    " , ans[i][1]);
            }
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
        
    int Ame__ = Ame_();
    
    int main(){;}
    

    暴力可得10分左右,Dij跑多源最短路,对于每个节点跑一个Dij,复杂度为(O(n^2log))

    考虑如何进行优化和选择算法,考虑提示信息

    为了方便选手写部分分,各个特殊性质的数据点中个位和十位均不相同,选手可据此来编写部分分代码。
    各边边权均为正数,保证int可存下
    

    可以得知spfa可以跑,并且数据经过了精心构造适合spfa跑考虑对每一个节点进行二进制压缩,对于二进制位相同的点并且歌曲种类相同的点作为起点跑最短路,分别求出二进制位相同或不同的点的最短路,跑8次最短路,若用Dij的话时间复杂度为(O(8nlog^2))
    看评测机心情可以跑过

  • 相关阅读:
    prototype.js超强的javascript类库
    MySQL Server Architecture
    Know more about RBA redo block address
    MySQL无处不在
    利用Oracle Enterprise Manager Cloud Control 12c创建DataGuard Standby
    LAMP Stack
    9i中DG remote archive可能导致Primary Database挂起
    Oracle数据库升级与补丁
    Oracle为何会发生归档日志archivelog大小远小于联机重做日志online redo log size的情况?
    Oracle Ksplice如何工作?How does Ksplice work?
  • 原文地址:https://www.cnblogs.com/Ame-sora/p/13406670.html
Copyright © 2011-2022 走看看