\(\mathcal{Description}\)

  Link.

  一条地铁线路上共 \(m\) 个站点,\(n\) 个人乘坐地铁,第 \(i\) 个人需要从 \(s_i\) 站坐到 \(e_i\) 站。你可以指挥他们在保证不走回头路的情况下走到某个站,或指挥处于同一个站的两人交换地铁卡。一张从 \(x\) 站进站 \(y\) 站出站的地铁卡花费为 \(|x-y|\),最小化花费和并给出可行方案。

  \(n\le10^5\),\(m\le10^6\),方案步骤数 \(\le 4\times10^5\)。

\(\mathcal{Solution}\)

  我切掉了,但没有完全切掉。

  画画图,在数轴上,画出向右行动的蓝色箭头和向左行动的红色箭头。注意到换卡本质上是交换始发站点,那么重合的红蓝箭头是能相互抵消的!如图:

\(\vec{AB},\vec{CD}\) 互换起点,变为 \(\vec{AE},\vec{CF}\),长度之和减少 \(2|DF|\),并且 \(\vec{AE},\vec{FC}\) 仍旧能与其他向量进行互换操作。

  不难证明,对于数轴上 \([k,k+1]\),覆盖它的红、蓝向量的数量的较小者就是这段区间被抵消的次数,且我们一定能构造方案取到这一下界,用向量总长减去它就求得最小花费。

  考虑方案的构造,注意到次数限制 \(4\times10^5=4\max\{n\}\),猜测“抵消”操作能够在 \(n\) 次换卡操作内完成,那么每次换卡就得让一个向量无法再与其他向量抵消。理性分析,我们分别维护蓝色向量和红色向量的小根堆,按 \((\text{左侧点},\text{右侧点})\) 的偏序关系分别取出最小者,设为 \(\boldsymbol u,\boldsymbol v\)。若它们没有公共区间则必然有一个已经无用;否则,分类讨论:

  • \(e(\boldsymbol u)\le s(\boldsymbol v)\),即红色向量右端点靠右,如图:

    \(\boldsymbol u=\vec{AB}\) 用完必然被丢掉,而 \(\vec{FD}\) 会被抵消,我们可以放心地让 \(A,C\) 在 \(B(F)\) 点会合换卡。但是!不能走回头路的限制带来一个问题:若存在 \(\vec{GH}\),\(C\) 就无法与 \(G\) 换卡了!

    解决方法形象而自然:红色向量向左而扫描方向向右,那么红色向量上的会合点不得不会从左到右出现,那我们反过来以栈的顺序指挥红色向量不就好啦?

  • \(e(\boldsymbol u)>s(\boldsymbol v)\),即蓝色向量的右端靠右,与上个情况恰好相反,我们需要立即将操作方案加入答案再做后续计算。

  最后,复杂度 \(\mathcal O(n\log n)\) 就能构造好方案啦。

\(\mathcal{Code}\)

/* Clearink */

#include <queue>
#include <cstdio>
#include <vector>
#include <cassert> #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) inline int rint() {
int x = 0, s = getchar();
for ( ; s < '0' || '9' < s; s = getchar() );
for ( ; '0' <= s && s <= '9'; s = getchar() ) x = x * 10 + ( s ^ '0' );
return x;
} template<typename Tp>
inline void wint( const Tp x ) {
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
} inline int imin( const int a, const int b ) { return a < b ? a : b; }
inline int imax( const int a, const int b ) { return a < b ? b : a; } typedef long long LL; const int MAXN = 1e5, MAXM = 1e6;
int n, m, s[MAXN + 5], e[MAXN + 5], fin[MAXN + 5]; struct Atom {
int l, r, id;
inline bool operator < ( const Atom& t ) const {
return !( l != t.l ? l <= t.l : ( r != t.r ? r <= t.r : id <= t.id ) );
}
};
std::priority_queue<Atom> seg[2];
std::vector<Atom> plan; inline void action( const Atom& u, const Atom& v, const int p ) {
if ( u.l != p ) plan.push_back( { u.id, p, 0 } );
if ( v.r + 1 != p ) plan.push_back( { v.id, p, 0 } );
plan.push_back( { u.id, v.id, 1 } );
} inline void solve( LL& ans ) { // strange...
if ( seg[0].empty() || seg[1].empty() ) return ;
Atom u( seg[0].top() ), v( seg[1].top() );
if ( u.r < v.l ) seg[0].pop(), solve( ans );
else if ( v.r < u.l ) seg[1].pop(), solve( ans );
else {
seg[0].pop(), seg[1].pop();
int il = imax( u.l, v.l ), ir = imin( u.r, v.r );
ans -= ir - il + 1 << 1; if ( u.r <= v.r ) {
if ( u.r < v.r ) seg[1].push( { u.r + 1, v.r, v.id } );
solve( ans ), action( u, v, u.r + 1 );
} else {
if ( v.r < u.r ) seg[0].push( { v.r + 1, u.r, u.id } );
action( u, v, v.r + 1 ), solve( ans );
}
}
} int main() {
freopen( "subway.in", "r", stdin );
freopen( "subway.out", "w", stdout ); for ( int T = rint(); T--; ) {
n = rint(), m = rint();
for ( ; !seg[0].empty(); seg[0].pop() );
for ( ; !seg[1].empty(); seg[1].pop() );
plan.clear(); LL ans = 0;
rep ( i, 1, n ) {
fin[i] = s[i] = rint(), e[i] = rint();
if ( s[i] < e[i] ) {
ans += e[i] - s[i], seg[0].push( { s[i], e[i] - 1, i } );
} else {
ans += s[i] - e[i], seg[1].push( { e[i], s[i] - 1, i } );
}
} solve( ans ); wint( ans ), putchar( ' ' );
for ( const Atom& a: plan ) if ( !a.id ) fin[a.l] = a.r;
rep ( i, 1, n ) if ( fin[i] != e[i] ) {
plan.push_back( { i, e[i], 0 } );
}
assert( plan.size() <= 4e5 );
wint( plan.size() ), putchar( '\n' );
for ( const Atom& a: plan ) {
wint( a.id ), putchar( ' ' );
wint( a.l ), putchar( ' ' );
wint( a.r ), putchar( '\n' );
}
}
return 0;
}

\(\mathcal{Details}\)

  挺逗的,考场上想到了逆序操作却忽略了一部分操作需要正序,“对称”的坑点只注意到一个……补题发现把循环换成代码里的递归再调一调语句顺序就过了。长记性呐。

Solution -「多校联训」战神归来的更多相关文章

  1. Solution -「多校联训」排水系统

    \(\mathcal{Description}\)   Link.   在 NOIP 2020 A 的基础上,每条边赋权值 \(a_i\),随机恰好一条边断掉,第 \(i\) 条段的概率正比于 \(a ...

  2. Solution -「多校联训」I Love Random

    \(\mathcal{Description}\)   给定排列 \(\{p_n\}\),可以在其上进行若干次操作,每次选取 \([l,r]\),把其中所有元素变为原区间最小值,求能够得到的所有不同序 ...

  3. Solution -「多校联训」签到题

    \(\mathcal{Description}\)   Link.   给定二分图 \(G=(X\cup Y,E)\),求对于边的一个染色 \(f:E\rightarrow\{1,2,\dots,c\ ...

  4. Solution -「多校联训」朝鲜时蔬

    \(\mathcal{Description}\)   Link.   破案了,朝鲜时蔬 = 超现实树!(指写得像那什么一样的题面.   对于整数集 \(X\),定义其 好子集 为满足 \(Y\sub ...

  5. Solution -「多校联训」消失的运算符

    \(\mathcal{Description}\)   Link.   给定长度为 \(n\) 的合法表达式序列 \(s\),其中数字仅有一位正数,运算符仅有 - 作为占位.求将其中恰好 \(k\) ...

  6. Solution -「多校联训」假人

    \(\mathcal{Description}\)   Link.   一种物品有 长度 和 权值 两种属性,现给定 \(n\) 组物品,第 \(i\) 组有 \(k_i\) 个,分别为 \((1,a ...

  7. Solution -「多校联训」古老的序列问题

    \(\mathcal{Description}\)   Link.   给定序列 \(\{a_n\}\),和 \(q\) 次形如 \([L,R]\) 的询问,每次回答 \[\sum_{[l,r]\su ...

  8. Solution -「多校联训」Sample

    \(\mathcal{Description}\)   Link   (稍作简化:)对于变量 \(p_{1..n}\),满足 \(p_i\in[0,1],~\sum p_i=1\) 时,求 \(\ma ...

  9. Solution -「多校联训」光影交错

    \(\mathcal{Description}\)   Link.   一个游戏包含若干次卡牌抽取,每次以 \(p_l\) 的概率得到 \(+1\),\(p_d\) 的概率得到 \(-1\),否则得到 ...

随机推荐

  1. vue-cli 在IE下兼容设置

    最近我们的项目选择用vue来做开发,在这个过程IE兼容性 首先我们按照步骤来安装vue-cli 创建项目运行 npm install npm run dev 然后我们在ie9下打开发现没有用但是vue ...

  2. println打印的原理

    由于out是System类中的一个不可变的变量 println方法在PrintStream类中 并且在打印都时候都会转换成字符串

  3. kafka学习笔记(五)kafka的请求处理模块

    概述 现在介绍学习一下kafka的请求处理模块,请求处理模块就是网络请求处理和api处理,这是kafka无论是对客户端还是集群内部都是非常重要的模块.现在我们对他进行源码深入探讨.当我们说到 Kafk ...

  4. postman设置token等关联参数

    登陆时登录成功后服务器会返回一个token,这个token作为第二步骤的入参:第二个步骤请求成功后服务器会返回一个新token,然后这个token作为第三步骤的入参!如此一来的话,要用postman做 ...

  5. QT控件之QSlider

    singleStep:比如按下键盘的左右建,每次移动的距离 pageStep:比如用鼠标对准滑动条的前面按下,每次移动的距离 value:初始默认值 接下来看该控件拥有的信号: 重点看后面的四个,看字 ...

  6. gin中如何自定义验证器

    package main import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding&qu ...

  7. Apple历代Mac系统汇总

    编号 系统名 版本号 名称 发布时间 01 macOS 11.0 Big Sur(大惊喜) 2020年6月 02 macOS 10.15 Catalina(卡特琳娜) 2019年9月 03 macOS ...

  8. 为什么ConcurrentHashMap是线程安全的?

    ConcurrentHashMap 是 HashMap 的多线程版本,HashMap 在并发操作时会有各种问题,比如死循环问题.数据覆盖等问题.而这些问题,只要使用 ConcurrentHashMap ...

  9. 从服务端生成Excel电子表格(Node.js+SpreadJS)

    Node.js是一个基于Chrome V8引擎的JavaScript运行环境,通常用于创建网络应用程序.它可以同时处理多个连接,并且不像其他大多数模型那样依赖线程. 对于 Web 开发者来说,从数据库 ...

  10. cygwin -- 在windows平台上运行的unix模拟环境

    cygwin是一个在windows平台上运行的unix模拟环境,是cygnus solutions公司开发的自由软件(该公司开发了很多好东西,著名的还有eCos,不过现已被Redhat收购).它对于学 ...