思路:

首先对于单个查询(k, p)来说,答案一定是a数组中的前k大数。如果第k大的数字有多个怎么办?取索引最小的若干个。所以我们只需对a数组按照值降序,索引升序排序即可。

多个查询怎么办?离线处理。依然是对数组a按照上面的方法排序,然后对所有的查询按照k升序排序,分别离线计算。具体做法是,按顺序扫描a,用一个集合动态维护前k大的数,当发现某个查询正好询问前k大时,即时处理即可。

那么如何从一个集合中快速找到第k大数?c++标准库中原始的set是不行的,可以用1. 二分+树状数组(或线段树)2. __gnu_pbds https://www.geeksforgeeks.org/ordered-set-gnu-c-pbds/

实现1(二分+树状数组,n * log(n) * log(n)):

 #include <bits/stdc++.h>

 using namespace std;
const int MAXN = ;
typedef pair<int, int> pii; int a[MAXN + ], bit[MAXN + ]; int lowbit(int x) { return x & -x; } void add(int i, int x)
{
while (i <= MAXN) { bit[i] += x; i += lowbit(i); }
} int sum(int i)
{
int ans = ;
while (i) { ans += bit[i]; i -= lowbit(i); }
return ans;
} bool cmp(pii& a, pii& b)
{
if (a.first != b.first) return a.first > b.first;
return a.second < b.second;
} void work(pii& q, map<pii, int>& mp)
{
int k = q.first, p = q.second;
int l = , r = MAXN, res = -;
while (l <= r)
{
int m = l + r >> ;
if (sum(m) < p) l = m + ;
else { res = m; r = m - ; }
}
assert(res != -);
mp[q] = res;
} int main()
{
ios::sync_with_stdio(false);
int n, m;
while (cin >> n)
{
memset(bit, , sizeof bit);
vector<int> a(n);
for (int i = ; i < n; i++) cin >> a[i];
vector<pii> b(n);
for (int i = ; i < n; i++) { b[i].first = a[i]; b[i].second = i + ; }
sort(b.begin(), b.end(), cmp);
cin >> m;
vector<pii> q(m);
for (int i = ; i < m; i++) cin >> q[i].first >> q[i].second;
vector<pii> sorted_q(q.begin(), q.end());
sort(sorted_q.begin(), sorted_q.end());
map<pii, int> res;
int cur = ;
for (int i = ; i < n; i++)
{
add(b[i].second, );
while (cur < m && i + == sorted_q[cur].first)
{
work(sorted_q[cur], res);
cur++;
}
}
for (auto it: q)
{
int id = res[it];
cout << a[id - ] << endl;
}
}
return ;
}

实现2(__gnu_pbds,n * log(n)):

 #include <bits/stdc++.h>

 #include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp> using namespace std;
using namespace __gnu_pbds; typedef pair<int, int> pii;
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set; bool cmp(pii& a, pii& b)
{
if (a.first != b.first) return a.first > b.first;
return a.second < b.second;
} int main()
{
ios::sync_with_stdio(false);
int n, m;
while (cin >> n)
{
vector<int> a(n);
for (int i = ; i < n; i++) cin >> a[i];
vector<pii> b(n);
for (int i = ; i < n; i++) { b[i].first = a[i]; b[i].second = i + ; }
sort(b.begin(), b.end(), cmp);
cin >> m;
vector<pii> q(m);
for (int i = ; i < m; i++) cin >> q[i].first >> q[i].second;
vector<pii> sorted_q(q.begin(), q.end());
sort(sorted_q.begin(), sorted_q.end());
map<pii, int> res;
int cur = ;
ordered_set st;
for (int i = ; i < n; i++)
{
st.insert(b[i].second);
while (cur < m && i + == sorted_q[cur].first)
{
res[sorted_q[cur]] = *st.find_by_order(sorted_q[cur].second - );
cur++;
}
}
for (auto it: q)
{
cout << a[res[it] - ] << endl;
}
}
}

CF1227D Optimal Subsequences的更多相关文章

  1. Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) D2. Optimal Subsequences (Hard Version) 数据结构 贪心

    D2. Optimal Subsequences (Hard Version) This is the harder version of the problem. In this version, ...

  2. CF-Technocup3 D Optimal Subsequences

    D Optimal Subsequences http://codeforces.com/contest/1227/problem/D2 显然,每次求的k一定是这个序列从大到小排序后前k大的元素. 考 ...

  3. Codeforces 1262D Optimal Subsequences(BIT+二分)

    首先比较容易想到肯定是前k大的元素,那么我们可以先对其进行sort,如果数值一样返回下标小的(见题意),接下里处理的时候我们发现需要将一个元素下标插入到有序序列并且需要访问第几个元素是什么,那么我们可 ...

  4. Optimal Subsequences(主席树)

    题意: 给定一个序列,长度为n(<=2e5),有m(<=2e5)个询问,每个询问包含k和pos,要从原序列中选出一个长度为k的子序列,要求是这个序列的和是所有长度为k的序列中最大的,且是字 ...

  5. D2. Optimal Subsequences (Hard Version) 主席树

    题目链接:https://codeforces.com/contest/1262/problem/D2 将数组按大到小排序(相同大小的按下标由小到大排序),依次将排序后的每个数在原数组中的位置放入主席 ...

  6. Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) - D2. Optimal Subsequences (Hard Version)(主席树)

    题意:一共有$n$个数,$m$次询问,每次询问包括$k.pos$两个数,需要你从这$n$个数里面找出$k$个数,使得他们的总和最大,如果有多种情况,找出序号字典序最小的一组,然后输出这个序列中第$po ...

  7. codeforces 1262D Optimal Subsequences 主席树询问第k小

    题意 给定长度为\(n\)的序列\(a\),以及m个询问\(<k,pos>\),每次询问满足下列条件的子序列中第\(pos\)位的值为多少. 子序列长度为\(k\) 序列和是所有长度为\( ...

  8. Codeforces Round #602 Div2 D1. Optimal Subsequences (Easy Version)

    题意:给你一个数组a,询问m次,每次返回长度为k的和最大的子序列(要求字典序最小)的pos位置上的数字. 题解:和最大的子序列很简单,排个序就行,但是题目要求字典序最小,那我们在刚开始的时候先记录每个 ...

  9. 笔记 - 数据结构 - 区间第k大

    Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) D2 - Optimal Subsequence ...

随机推荐

  1. D. Vasya and Triangle(思维, 三角形)

    传送门 题意: 给你 n, m, k, 问你是否存在一个三角形, 满足三角形的面积等于 n * m / k: 若存在, 输出YES, 且输出满足条件的三角形的三个坐标(答案有多种,则输出任意一种)   ...

  2. C# 可为空?及(??、?. )

    可空类型修饰符(?): 引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空. 例如:string str=null; 是正确的,int i=null; 编译器就会报错. 为了使值类型也 ...

  3. noi.ac #43 dp计数

    \(sol\) 状态 \[f_{i, dis_1, dis_2, dis_3, dis_4}\] 表示到了第 \(i\) 层,其中 \(dis_{1}\) 表示第一根柱子剩下的最靠上的横木到当前 \( ...

  4. linux 查看内存,free,ps,说明Buffers,Cached,SReclaimable

    查看机器剩余内存free即可,百度就可以轻松查到,主要想说的 查所有进程占用内存情况并排序: ps aux | sort -nk5 k5代表根据RSS排序,k6代表VSZ排序. ----------- ...

  5. 未公开函数 NtQuerySystemInfoMation 遍历进程信息,获得进程的用户名(如: system,Admin..)

    目录 遍历进程用户名 代码例子 遍历进程用户名 代码例子 #include <windows.h> #include <iostream> #include <COMDE ...

  6. 在Maven项目中使用lombok

    事前准备:如果是eclipse的话,需要在官网下载jar文件,放到eclipse根目录下,eclipse.ini的最后追加 -Xbootclasspath/a:lombok.jar -javaagen ...

  7. ubuntu之路——day2

    一:sougou输入法安装 详情参考:https://blog.csdn.net/xin17863935225/article/details/82285177 注意切换成fcitx架构 因为linu ...

  8. css中的浮动与定位

    传送门:https://www.cnblogs.com/junwuyao/p/7435257.html

  9. 作业要求2018092609-2 选题 Scrum立会报告+燃尽图 05

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/8678 一.小组情况组长:贺敬文组员:彭思雨 王志文 位军营 杨萍队名:胜 ...

  10. 第1课_Java基础知识【学习笔记】

    摘要:韦东山android视频学习笔记 一.android系统的基本框架如图一所示,应用程序是用java编写的,底层驱动是用C代码写的,java与C怎么连接在一起主要是通过本地服务.android系统 ...