luogu 3730
题目背景
will在曼哈顿开了一家交易所,每天,前来买卖股票的人络绎不绝。
现在,will想要了解持股的情况。由于来交♂易的人实在是太多了,需要你写一个程序来帮他完成这个任务。
题目描述
-
前来交易的N个人排成了一行,为了简便起见,每个人都只持有一种股票。
-
不同的的人可能会持有相同的股票。
-
定义一种股票的热度为持有该股票的人数。
- 每次,will会给出这样的询问:在一段连续区间的人之中,热度第k小的股票的热度是多少?
输入输出格式
输入格式:
-
第一行两个正整数N,M,分别表示人数和询问的次数;
-
接下来一行N个正整数,表示每个人所持的股票 a_iai。
- 接下来M行,每行三个正整数l,r,k,表示询问区间[l, r][l,r]中的第k小的热度,保证l\leq rl≤r。
输出格式:
-
对于每个询问,输出一行一个数,表示区间[l, r]中的第k小的热度值。
- 如果k大于区间里股票的种类数,输出-1。
输入输出样例
说明
对于20%的数据,N,M≤1000;
对于另外10%的数据,所有的l=1,r=N;
对于100%的数据,N,M≤100000,ai≤109;
链接:https://www.luogu.org/problemnew/show/3730
赛前,来一波暴力分块大法好啊
莫队算法套分块查询.
对于n个数离散化后,它们的值域在[1,n]
考虑如果题目问的是区间众数查询.
那么,这就是莫队入门经典题.
我们会对每个数的出现次数的个数放入一个新数组维护,并进行统计
那么,我们可以对这新数组分块进行维护,分成(√n)块.
莫队算法进行移动时,对于单点进行修改,所在的块的信息也进行修改
对于询问时先在块上暴力跳,直到不能跳为止,再在点上跳.
这样复杂度为O(n√n).
AC代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #include<stdio.h> #include<iostream> #include<math.h> #include<algorithm> #define BIG 200011 #define FOR(i,s,t) for(register int i=s;i<=t;++i) using std::sort; using std::unique; using std::lower_bound; int hv[BIG],f[BIG],a[BIG],b[BIG],ans[BIG],bl[BIG],sum[BIG]; int n,m,blo,cnt; class node{ public : int l,r,k,bs; inline bool operator <(node A) const { if (bl[l]!=bl[A.l]) return bl[l]<bl[A.l]; if (bl[r]!=bl[A.r]) return bl[r]<bl[A.r]; return k<A.k; } }q[BIG]; int l,r,p; inline void update( int pos, int w){ --sum[bl[hv[a[pos]]]]; --f[hv[a[pos]]]; w?++hv[a[pos]]:--hv[a[pos]]; ++sum[bl[hv[a[pos]]]]; ++f[hv[a[pos]]]; } inline int query( int k){ register int i; for (i=1;i<=blo;++i) if (k-sum[i]>0) k-=sum[i]; else break ; for (register int j=(i-1)*blo+1;j<=i*blo;++j){ k-=f[j]; if (k<=0) return j; } return -1; } int main(){ scanf( "%d%d" ,&n,&m); blo=sqrt(n); FOR(i,1,n)bl[i]=(i-1)/blo+1; FOR(i,1,n)scanf( "%d" ,a+i),b[i]=a[i]; sort(b+1,b+n+1); cnt=unique(b+1,b+n+1)-b-1; FOR(i,1,n)a[i]=lower_bound(b+1,b+cnt+1,a[i])-b; FOR(i,1,m)scanf( "%d%d%d" ,&q[i].l,&q[i].r,&q[i].k),q[i].bs=i; sort(q+1,q+m+1); l=1,r=0; FOR(i,1,m){ while (l<q[i].l)update(l++,0); while (q[i].l<l)update(--l,1); while (r<q[i].r)update(++r,1); while (q[i].r<r)update(r--,0); ans[q[i].bs]=query(q[i].k); } FOR(i,1,m)printf( "%d\n" ,ans[i]); return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· golang自带的死锁检测并非银弹
· 聊一聊 C#异步 任务延续的三种底层玩法
· 上位机能不能替代PLC呢?
· 2024年终总结:5000 Star,10w 下载量,这是我交出的开源答卷
· 一个适用于 .NET 的开源整洁架构项目模板
· .NET Core:架构、特性和优势详解