题目背景
(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))
看评测机心情可以跑过