P4559 [JSOI2018]列队
\(\color{#0066ff}{ 题目描述 }\)
作为一名大学生,九条可怜在去年参加了她人生中的最后一次军训。
军训中的一个重要项目是练习列队,为了训练学生,教官给每一个学生分配了一个休息位置。每次训练开始前,所有学生都在各自的休息位置休息,但是当教官发出集合命令后,被点到的学生必须要到指定位置集合。
为了简化问题,我们把休息位置和集合位置抽象成一根数轴。一共有 \(n\) 个学生,第 \(i\) 个学生的休息位置是 \(a_i\)。每一次命令,教官会指定一个区间 \([l,r]\) 和集合点 \(K\) ,所有编号在 \([l,r]\) 内的学生都必须赶到集合点列队。在列队时,每一个学生需要选择 \([K,K+r-l]\) 中的一个整数坐标站定且不能有任何两个学生选择的坐标相同。学生从坐标 \(x\) 跑到坐标 \(y\) 需要耗费体力 \(\vert y-x \vert\) 。
在一天的训练中,教官一共发布了 \(m\) 条命令 \((l,r,K)\) ,现在你需要计算对于每一条命令,在所有可能的列队方案中,消耗的体力值总和最小是多少。
以下是对题意的一些补充:
- 任何两条命令是无关的,即在一条集合命令结束后,所有学生都会回到自己的休息位置,然后教官才会发出下一条命令。
- 在集合的时候,可能有编号不在 \([l,r]\) 内的学生处在区间 \([K,K+r-l]\) 中,这时他会自己跑开,且跑动的距离不记在消耗的体力值总和中。
\(\color{#0066ff}{输入格式}\)
第一行输入两个整数 \(n,m\)。
第二行 \(n\) 个整数 \(a_i\) 表示学生的休息位置。保证学生休息的位置两两不同。
接下来 \(m\) 行每行三个整数 \(l,r,K\) 表示一条命令。
\(\color{#0066ff}{输出格式}\)
对于每一条命令输出一行一个整数表示最小的体力值总和。
\(\color{#0066ff}{输入样例}\)
5 5
1 5 7 6 2
1 5 2
1 5 3
1 3 9
2 4 2
3 5 5
\(\color{#0066ff}{输出样例}\)
5
4
17
9
3
\(\color{#0066ff}{数据范围与提示}\)
在第一条命令中,五名学生依次跑到 \([2,5,4,6,3]\),则总代价为 |2-1|+|5-5|+|4-7|+|6-6|+|3-2|=5∣2−1∣+∣5−5∣+∣4−7∣+∣6−6∣+∣3−2∣=5。
在第二条命令中,五名学生依次跑到 \([4,5,7,6,3]\),则总代价为 |4-1|+|5-5|+|7-7|+|6-6|+|3-2|=4∣4−1∣+∣5−5∣+∣7−7∣+∣6−6∣+∣3−2∣=4。
在第三条命令中,三名学生依次跑到 \([11,10,9]\),则总代价为 |11-1|+|10-5|+|9-7|=17∣11−1∣+∣10−5∣+∣9−7∣=17。
在第四条命令中,三名学生依次跑到 \([4,2,3]\),则总代价为 |4-5|+|2-7|+|3-6|=9∣4−5∣+∣2−7∣+∣3−6∣=9。
在第五条命令中,三名学生依次跑到 \([7,6,5]\),则总代价为 |7-7|+|6-6|+|5-2|=3∣7−7∣+∣6−6∣+∣5−2∣=3。
对于10%的数据\(n,m \leq 10\)。
对于 \(40\%\) 的数据,\(n,m \leq 10^3\)。
对于 \(70\%\) 的数据,\(n,m \leq 10^5\)。
对于 \(100\%\) 的数据,\(n,m \leq 5 \times 10^5,1 \leq a_i,K \leq 10^6\)。
对于 \(100\%\) 的数据,学生休息的位置两两不同。
\(\color{#0066ff}{ 题解 }\)
不难想到用主席树维护
设当前人的范围为\([l,r]\),它们要到\([ql,qr]\)去
我们维护区间人的个数,这左子树有num个人,则可以递归\([l,mid][ql,ql+num-1]和[mid +1,r][ql+num,qr]\)
这复杂度。。。。\(O(n^2)\)啊。。。
进而考虑剪掉一些东西,比如\(r\leq ql, l\ge qr\)
拿\(r\le ql\)举个例子,让所有人到ql集合,然后一个一个往后走,就是个等差数列很好求
这样对于强数据还是会被卡
进而想一想,\(r\le qr\)能不能优化呢? 答案是肯定的
让所有人跑到qr,然后往回退体力,这种情况下每个人只会跑多不会跑少,所以可以直接减
分析一下这样做的复杂度
当\(mid \le ql +num-1\)时,左子树\(O(1)\)return,右子树\(O(logn)\)递归,反之同理
因此\(O(nlogn)\)可过!
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 2e6 + 100;
struct Tree {
protected:
struct node {
int num;
LL tot;
node *ch[2];
node() { num = tot = 0; ch[0] = ch[1] = NULL; }
};
node *root[maxn];
int len;
void add(node *&o, node *lst, int l, int r, LL p) {
o = new node();
*o = *lst;
o->num++, o->tot += p;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) add(o->ch[0], lst->ch[0], l, mid, p);
else add(o->ch[1], lst->ch[1], mid + 1, r, p);
}
LL getsum(LL l, LL r) {
return (r - l + 1) * (r - l) >> 1;
}
LL getans(node *x, node *y, LL l, LL r, LL ql, LL qr) {
if(ql > qr) return 0;
if(r <= qr) return qr * (qr - ql + 1) - (y->tot - x->tot) - getsum(ql, qr);
if(l >= ql) return (y->tot - x->tot) - ql * (qr - ql + 1) - getsum(ql, qr);
int num = y->ch[0]->num - x->ch[0]->num;
int mid = (l + r) >> 1;
return getans(x->ch[0], y->ch[0], l, mid, ql, ql + num - 1) + getans(x->ch[1], y->ch[1], mid + 1, r, ql + num, qr);
}
public:
void init(int n, LL *a) {
len = 1e6 + 10;
root[0] = new node();
root[0]->ch[0] = root[0]->ch[1] = root[0];
for(int i = 1; i <= n; i++) add(root[i], root[i - 1], 1, len, a[i]);
}
LL getans(int l, int r, int k) { return getans(root[l - 1], root[r], 1, len, k, k + r - l); }
}s;
LL a[maxn], n, m;
int main() {
n = in(), m = in();
for(int i = 1; i <= n; i++) a[i] = in();
s.init(n, a);
LL l, r, k;
while(m --> 0) {
l = in(), r = in(), k = in();
printf("%lld\n", s.getans(l, r, k));
}
return 0;
}
P4559 [JSOI2018]列队的更多相关文章
- 洛谷P4559 [JSOI2018]列队 【70分二分 + 主席树】
题目链接 洛谷P4559 题解 只会做\(70\)分的\(O(nlog^2n)\) 如果本来就在区间内的人是不用动的,区间右边的人往区间最右的那些空位跑,区间左边的人往区间最左的那些空位跑 找到这些空 ...
- 洛谷P4559 [JSOI2018]列队(主席树)
题面 传送门 题解 首先考虑一个贪心,我们把所有的人按\(a_i\)排个序,那么排序后的第一个人到\(k\),第二个人到\(k+1\),...,第\(i\)个人到\(k+i-1\),易证这样一定是最优 ...
- [JSOI2018]列队
Description: 作为一名大学生,九条可怜在去年参加了她人生中的最后一次军训. 军训中的一个重要项目是练习列队,为了训练学生,教官给每一个学生分配了一个休息位置.每次训练开始前,所有学生都在各 ...
- [JSOI2018]列队(主席树)
跟上次那道列队不一样,但都是九条可怜...(吉老师太强了) 在主席树上统计答案,因为值域只有 \(10^6\) 甚至不用离散化... \(Code\ Below:\) #include <bit ...
- BZOJ5319 JSOI2018列队(主席树)
显然集合后相对位置不变最优.主席树上二分向左和向右的分界点即可.注意主席树的值域.我怎么天天就写点一眼题啊. #include<iostream> #include<cstdio&g ...
- 洛谷 P4559: bzoj 5319: [JSOI2018]军训列队
题目传送门:洛谷 P4559. 题意简述: 有 \(n\) 个学生,编号为 \(i\) 的学生有一个位置 \(a_i\). 有 \(m\) 个询问,每次询问编号在 \([l,r]\) 区间内的学生跑到 ...
- [JSOI2018]军训列队
[JSOI2018]军训列队 题目大意: \(n(n\le5\times10^5)\)个学生排成一排,第\(i\)个学生的位置为\(a_i\).\(m(m\le5\times10^5)\)次命令,每次 ...
- BZOJ5319: [Jsoi2018]军训列队
BZOJ5319: [Jsoi2018]军训列队 https://lydsy.com/JudgeOnline/problem.php?id=5319 分析: 易知把所有人按原本的顺序放到\([K,K+ ...
- BZOJ5319 & 洛谷4559 & LOJ2551:[JSOI2018]军训列队——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5319 https://www.luogu.org/problemnew/show/P4559 ht ...
随机推荐
- Jconsole 测试.
Jconsole 测试. 1 下载并安装 d:\Program Files\Java\jdk1.8.0_111\ JDK自带,Windows下图形界面,监控分析Java程序 2 查看jmx进程号 [r ...
- 50 states of America
美国州名 州名英文 州名音标 简写 首府 首府 阿拉巴马州 Alabama [ˌæləˈbæmə] AL 蒙哥马利 Montgomery[mənt'gʌməri] 阿拉斯加州 Alaska [ ...
- VisualGDB系列10:快速调试Linux应用程序
根据VisualGDB官网(https://visualgdb.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指正. 本文介绍如何快速调试GCC构建的Linu ...
- Visual Studio 小工具
折叠解决方案的每个项(Collapse Solution) 功能:折叠解决方案视图窗口中的解决方案或项目级别的每个项.包括嵌套在解决方案文件夹中的子项,引用和属性文件夹扩展节点. 源代码的文件头实现方 ...
- Python-使用unrar库时Couldn't find path to unrar library的解决办法
在Pycharm安装完unrar后,还要安装rar官方的库 不然运行的时候会抛出Couldn't find path to unrar library的错误 Windows: 下载rarlib的库文件 ...
- 新建 FrameMaker API 时引用目录的设置
如果将FDK安装目录下的Sample项目拷贝到其它目录编译,往往会报错 c1083 找不到fapi.h等头文件,或者Link时报错找不到.lib文件. 1.可通过菜单-项目-xxx属性-配置属性-c/ ...
- 2015.1.4 判断鼠标点击DataGridView的第几行还是空白处
public int GetRowIndexAt(int mouseLocation_Y) { if (dvaw.FirstDisplayedScrollingRowIndex < 0) { r ...
- win 10 提升权限
问题:每次打开Visual Studio 提示,需要重启以获取管理员权限 解决: 1.Win+R 2.输入:gpedit.msc 3.windows设置->安全设置->本地策略->安 ...
- Python 面向对象 (进阶篇)
<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可 ...
- Oracle pl/sql 基础入门语法
PL/SQL是一种块结构的语言,这意味着PL/SQL程序被划分和编写代码的逻辑块.每块由三个子部分组成:1 声明 此部分开头使用关键字DECLARE.它是一个可选的部分,并限定在该程序中使用的 ...