题目链接

问题分析

比较明显的最短路模型。需要堆优化的dij。建图的时候注意细节就好。

参考程序

#include <bits/stdc++.h>
#define LL long long
//#define DEBUG
using namespace std; const int Maxn = 10010;
const int Maxm = 100010;
const int Maxk = 12;
struct edge {
int To, Next, Cost;
};
edge Edge[ Maxm << 1 ];
int Start[ Maxn ], Used;
int n, m, k, Tag[ Maxn ], Dis[ Maxn ][ Maxk << 1 ], s, t, Vis[ Maxn ][ Maxk << 1 ];
int DistK;
struct heap {
int Used, Tree[ Maxn * ( Maxk << 1 ) ], Ref[ Maxn * ( Maxk << 1 ) ];
void Clear() { Used = 0; return; }
bool Cmp( int x, int y ) {
return Dis[ x / DistK ][ x % DistK ] < Dis[ y / DistK ][ y % DistK ];
}
bool Empty() { return Used == 0; }
inline void Swap( int x, int y ) {
Ref[ Tree[ x ] ] = y;
Ref[ Tree[ y ] ] = x;
swap( Tree[ x ], Tree[ y ] );
return;
}
void Insert( int x ) {
++Used; Tree[ Used ] = x; Ref[ x ] = Used;
int Temp = Used;
for( ; Temp > 1; )
if( Cmp( Tree[ Temp ], Tree[ Temp >> 1 ] ) )
Swap( Temp, Temp >> 1 ), Temp >>= 1;
else
break;
return;
}
void Fresh( int x ) {
int Temp = Ref[ x ];
for( ; Temp > 1; )
if( Cmp( Tree[ Temp ], Tree[ Temp >> 1 ] ) )
Swap( Temp, Temp >> 1 ), Temp >>= 1;
else
break;
return;
}
int Top() { return Tree[ 1 ]; }
void Pop() {
Swap( 1, Used ); --Used;
int Temp = 1;
for( ; ( Temp << 1 ) <= Used; ) {
if( ( Temp << 1 | 1 ) > Used ) {
if( Cmp( Tree[ Temp << 1 ], Tree[ Temp ] ) )
Swap( Temp, Temp << 1 );
break;
}
if( Cmp( Tree[ Temp << 1 ], Tree[ Temp << 1 | 1 ] ) )
if( Cmp( Tree[ Temp << 1 ], Tree[ Temp ] ) ) {
Swap( Temp, Temp << 1 );
Temp <<= 1;
}
else
break;
else
if( Cmp( Tree[ Temp << 1 | 1 ], Tree[ Temp ] ) ) {
Swap( Temp, Temp << 1 | 1 );
Temp = Temp << 1 | 1;
}
else
break;
}
return;
}
};
heap Heap; void Clear() {
memset( Start, 0, sizeof( Start ) );
Used = 0;
memset( Dis, 255, sizeof( Dis ) );
Heap.Clear();
return;
} inline void AddEdge( int x, int y, int z ) {
Edge[ ++Used ] = ( edge ){ y, Start[ x ], z };
#ifdef DEBUG
printf( "AddEdge %d -> %d : %d\n", x, y, z );
#endif
Start[ x ] = Used;
return;
} void Init() {
scanf( "%d%d%d", &n, &m, &k );
++k;
for( int i = 1; i <= n; ++i ) scanf( "%d", &Tag[ i ] );
for( int i = 1; i <= n; ++i ) Tag[ i ] = ( Tag[ i ] == 1 ) ? -1 : 1;
for( int i = 1; i <= m; ++i ) {
int x, y, z; scanf( "%d%d%d", &x, &y, &z );
AddEdge( x, y, z ); AddEdge( y, x, z );
}
scanf( "%d%d", &s, &t );
DistK = k << 1;
return;
} void Work() {
Clear();
Init();
Dis[ s ][ k + Tag[ s ] ] = 0;
if( k + Tag[ s ] < 1 || k + Tag[ s ] >= DistK ) {
printf( "-1\n" );
return;
}
Heap.Insert( s * DistK + k + Tag[ s ] );
Vis[ s ][ k ] = 2;
for( ; !Heap.Empty(); ) {
int T = Heap.Top();
Heap.Pop();
int u = T / DistK;
Vis[ u ][ T % DistK ] = 1;
#ifdef DEBUG
printf( "Sol %d %d %d\n", u, T % DistK, Dis[ u ][ T % DistK ] );
#endif
for( int t = Start[ u ]; t; t = Edge[ t ].Next ) {
int v = Edge[ t ].To; int p = T % DistK + Tag[ v ];
if( p < 1 || p >= DistK ) continue;
if( Vis[ v ][ p ] == 1 ) continue;
if( Dis[ v ][ p ] == -1 ||
Dis[ v ][ p ] > Dis[ u ][ T % DistK ] + Edge[ t ].Cost ) {
Dis[ v ][ p ] = Dis[ u ][ T % DistK ] + Edge[ t ].Cost;
#ifdef DEBUG
printf( " Cha %d %d %d\n", v, p, Dis[ v ][ p ] );
#endif
if( Vis[ v ][ p ] == 2 ) Heap.Fresh( v * DistK + p );
else {
Heap.Insert( v * DistK + p );
Vis[ v ][ p ] = 2;
}
}
}
}
int Ans = -1;
for( int i = 1; i < DistK; ++i )
if( Dis[ t ][ i ] != -1 && ( Ans == -1 || Ans > Dis[ t ][ i ] ) )
Ans = Dis[ t ][ i ];
printf( "%d\n", Ans );
return;
} int main() {
int TestCases; scanf( "%d", &TestCases );
for( ; TestCases--; ) Work();
return 0;
}

「TJOI2019」大中锋的游乐场的更多相关文章

  1. [TJOI2019]大中锋的游乐场——最短路+DP

    题目链接: [TJOI2019]大中锋的游乐场 题目本质要求的还是最短路,但因为有第二维权值(汽水看成$+1$,汉堡看成$-1$)的限制,我们在最短路的基础上加上一维$f[i][j]$表示到达$i$节 ...

  2. 「ZJOI2016」大森林 解题报告

    「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...

  3. LOJ#2230. 「BJOI2014」大融合

    LOJ#2230. 「BJOI2014」大融合 题目描述 小强要在$N$个孤立的星球上建立起一套通信系统.这套通信系统就是连接$N$个点的一个树.这个树的边是一条一条添加上去的. 在某个时刻,一条边的 ...

  4. 【LOJ】#3109. 「TJOI2019」甲苯先生的线段树

    LOJ#3109. 「TJOI2019」甲苯先生的线段树 发现如果枚举路径两边的长度的话,如果根节点的值是$x$,左边走了$l$,右边走了$r$ 肯定答案会是$(2^{l + 1} + 2^{r + ...

  5. 【题解】Luogu P5340 [TJOI2019]大中锋的游乐场

    原题传送门 没想到省选也会出这种题??! 实际就是一个带有限制的最短路 因为\(k<=10\),所以我们珂以暴力将每个点的权值分为[-k,k],为了方便我们珂以转化成[0,2k],将汉堡的权值记 ...

  6. [洛谷P5340][TJOI2019]大中锋的游乐场

    题目大意:有$n(n\leqslant10^4)$个点,$m(m\leqslant10^5)$条边的无向图,每个点有一个属性$A/B$,要求$|cnt_A-cnt_B|\leqslant k(k\le ...

  7. luogu P5340 [TJOI2019]大中锋的游乐场

    传送门 要求经过路径汉堡的点和可乐的点个数之差绝对值\(\le k\),所以可以考虑dp,\(f_{i,j}\)表示到点\(i\),汉堡的点个数减可乐的点的个数为\(j\)的最短距离,注意一下负下标处 ...

  8. @loj - 2092@ 「ZJOI2016」大森林

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Y 家里有一个大森林,里面有 n 棵树,编号从 1 到 n. ...

  9. 【LOJ】#2230. 「BJOI2014」大融合

    题解 我现在真是太特么老年了 一写数据结构就颓废,难受 这题就是用lct维护子树 ???lct怎么维护子树 这样想,我们给每个点记录虚边所在的子树大小,只发生在Access和link的时候 这样的话我 ...

随机推荐

  1. java this的作用

    this: 区分成员变量和局部变量的重名问题,this.name指的是类中的成员变量,而不是方法内部的

  2. Eratosthenes筛法

    复杂度为nlogn. 算法思想为:枚举1~sqrt(n),然后把每一个数的倍数都都打上不是素数的标记. 还要特别注意0,1不是素数,打标记枚举到i*k<=n. 代码如下 #include< ...

  3. c++学习之对象和类——构造函数和析构函数

    再认真理一遍~ 0.类 这里先来定义一个类,便于后面的理解.参考C++ Primer Plus class Stock { private: std::string company; long sha ...

  4. linux安装git服务器和svn服务器

    linux版本 linux版本为CentOS 6.8 (要注意有些软件的安装方法在各个linux版本之间也是存在差异的) git服务器 git服务器需要提供一个UI供开发人员创建项目管理项目,选择使用 ...

  5. gitlab操作笔记

    基本命令 准备 1. 安装所需命令 sudo yum install curl openssh-server openssh-clients postfix cronie -y2. 安装SSH sud ...

  6. JDK8~13新特性概览

    JDK8 1. 接口default 与 static 关键字 /** * jdk8中接口可以使用声明default和static修饰的方法 * static修饰的方法和普通的方法一样,可以被直接调用 ...

  7. zookeeperAPI的常用方法

    zookeeper支持三种部署方式: 1 单机 2 集群 3 伪集群 删除节点 zkClient.delete(path);

  8. Linux系统定时备份网站文件到七牛云存储脚本

    1.七牛云账号注册. 有些朋友可能会问为什么要备份到七牛云?很简单,七牛云免费注册就能获取1G的存储空间,只要简单几步操作完成实名认证即可获取10G的存储空间,对于一般个人站点来说已经足够备份使用了. ...

  9. JavaScript金字塔打印

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. 如何去除List集合中的重复元素? a,b,c,a,c,b,d,,,,,,

    package com.fs.test; import java.util.ArrayList; import java.util.List; public class Listdemo { publ ...