http://acm.hdu.edu.cn/showproblem.php?pid=6040
这题题意也不太说人话。。。而且前期过的人太少了,最后一小时看懂了发现其实是一道很水的题
他的意思就是随机给你生成一堆数字,然后询问m次第bj+1小的是多大
n=1e7,T=10,m=100,所以排序nlogn*T直接1e9了,肯定不行的
那么这题的关键问题就是把你排序给卡了怎么快速的回答第bj+1小的值是哪个
了解k-d树这个东西后,我们可以知道区间第k大如果只需要知道值的话可以用nth_element这个东西来搞(2018我校校赛热身赛甚至出了个必须用fread和nth_element才能过的题。。。)
那么题目还给出了一个奇怪的条件,也就是如果存在bi<bk,bj<bk,且bi!=bj,那么bi+bj<=bk,就说明对于不同的两个值,要大于他们的值一定要比他们之和还大,那么b数组就是一个2次幂级别增大的东西,只需要排序,从大到小,每次nth_element一下前缀就行,因为nth_element会把第bj+1大的放到bj+1的位置,左边都是小于它的,右边都是大于他的,但是是无序的,具体内部实现我好像还不会。。。
那么由于区间是不断/2的,那么总共的区间长度之和最多就是2n
#include<bits/stdc++.h>
using namespace std;
const int maxl=1e7+10;
int n,m,cas;
unsigned A,B,C,a[maxl],ans[110];
struct node
{
int val,id;
}b[110];
unsigned x , y, z;
unsigned rng61() {
unsigned t;
x ^= x << 16;
x ^= x >> 5;
x ^= x << 1;
t = x;
x = y;
y = z;
z = t ^ x ^ y;
return z;
}
inline bool cmp(const node &a,const node &b)
{
if(a.val==b.val)
return a.id<b.id;
return a.val<b.val;
}
inline void prework()
{
scanf("%u%u%u",&A,&B,&C);
for(int i=1;i<=m;i++)
scanf("%d",&b[i].val),b[i].id=i;;
sort(b+1,b+1+m,cmp);
x = A, y = B, z = C;
for(register int i=1;i<=n;++i)
a[i]=rng61();
int last=n;
for(int i=m;i>=1;i--)
{
if(i+1<=m && b[i+1].val==b[i].val)
{
ans[b[i].id]=a[b[i].val+1];
}
else
{
nth_element(a+1,a+b[i].val+1,a+1+last);
ans[b[i].id]=a[b[i].val+1];
last=b[i].val+1;
}
}
}
inline void mainwork()
{
}
inline void print()
{
++cas;
printf("Case #%d:",cas);
for(int i=1;i<=m;i++)
printf(" %u",ans[i]);
puts("");
}
int main()
{
int t=1;
while(~scanf("%d%d",&n,&m))
{
prework();
mainwork();
print();
}
return 0;
}
本文解析了一道关于快速查找第k小元素的问题,利用nth_element及排序技巧,在大规模数据集上实现了高效求解。通过分析题目特点,采用特殊排序策略和k-d树思想解决传统排序无法应对的大规模查询问题。
764

被折叠的 条评论
为什么被折叠?



