题目链接

问题分析

比较明显的最短路模型。需要堆优化的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. HTML(上)

    目录 HTML(上) 浏览器 HTML 什么是HTML HTML的作用 编写HTML的规范 HTML结构 HTML常用标签 HTML标签速记 HTML(上) 浏览器 浏览器也是一个客户端 #这是一个服 ...

  2. 常用的TCP/UDP端口

    已知的TCP/UDP端口可以在wikipedia上找到: List of TCP and UDP port numbers, 太多了,按组列举了最常用的,如下: FTP:21SSH:22Telnet: ...

  3. Redis原子计数器incr,防止并发请求

    转自:https://blog.csdn.net/Roy_70/article/details/78260826 一.前言在一些对高并发请求有限制的系统或者功能里,比如说秒杀活动,或者一些网站返回的当 ...

  4. es6编译器(babel搭建)

    1.安装Node.js,初始化项目 npm init -y 2.安装babel-cli(兼容至ie7) npm i @babel/core @babel/cli @babel/preset-env - ...

  5. CXF实现webService服务(一)

    以前工作中也用CXF,但都是用别人现成搭好的环境,这次自己重头搭建一遍环境.过程中也有遇到的问题,也做了简单的整理. 对于CXF是干什么用的,我不想多说,大家都知道这是我们在Java编程中webSer ...

  6. react 不同环境配置不同域名

    npm eject 先将配置文件暴露出来 将scripts中的build文件复制一份,改名为你需要的名字 将其中的 process.env.NODE_ENV 赋值为你需要的环境 在package.js ...

  7. Mybatis分页-利用Mybatis Generator插件生成基于数据库方言的分页语句,统计记录总数 (转)

    众所周知,Mybatis本身没有提供基于数据库方言的分页功能,而是基于JDBC的游标分页,很容易出现性能问题.网上有很多分页的解决方案,不外乎是基于Mybatis本机的插件机制,通过拦截Sql做分页. ...

  8. mysql的auto-rehash简介

    今天在看mysql的配置文件的时候,发现有"auto-rehash"不明白什么意思,在此记录一下,auto-rehash是自动补全的意思,就像我们在linux命令行里输入命令的时候 ...

  9. 13、Nginx七层负载均衡

    1.Nginx负载均衡基本概述 1.1为什么需要使用负载均衡 当我们的Web服务器直接面向用户,往往要承载大量并发请求,单台服务器难以负荷,我使用多台WEB服务器组成集群,前端使用Nginx负载均衡, ...

  10. php和redis实现消息队列

    php+redis消息队列是php+mysql性能不足时的一个中间间处理方案.通过这个中间的处理,保证的数据的可用性和准确性.用于服务器瞬间请求大,数据库压力大的情况.如并发量大导致的超卖.并发量大导 ...