题解 P3730 曼哈顿交易
RuntimeErr · · 题解
蒟蒻的莫队+值域分块题解
保证简单易懂!
题意简化
令
思路
考虑值域分块,注意值域是持有某种股票的人数(热度),所以范围是不超过
考虑
//be是对应的块
//两个函数前半段都是去掉原来的贡献,后半段都是加上新的贡献
inline void add(int x){
--cnt2[cnt1[x]];
--tot[be[cnt1[x]]];
++cnt2[++cnt1[x]];//唯一的区别就是这一句了
++tot[be[cnt1[x]]];
}
inline void del(int x){
--cnt2[cnt1[x]];
--tot[be[cnt1[x]]];
++cnt2[--cnt1[x]];
++tot[be[cnt1[x]]];
}
再来看查询部分,我们先按块查,把查询的
inline int get(int k){
int i;
for(i=1;i<=num;++i){//num是块数
if(k-tot[i]<=0)break;//找到了就退出
k-=tot[i];
}
if(i==num+1)return -1;//所有块都查完了还没找到就返回-1
for(int j=L[i];j<=R[i];++j){
if(k-cnt2[j]<=0)return j;//找到了就返回
k-=cnt2[j];
}
}
!!!值域甚大,须离散化
Code:
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e5+10;
int n,m,a[N],b[N],ans[N];
int bl,L[N],R[N],be[N],num,tot[N],cnt1[N],cnt2[N];
struct query{int l,r,k,id;}q[N];
inline bool cmp(query a,query b){
return be[a.l]^be[b.l]?a.l<b.l:be[a.l]&1?a.r<b.r:a.r>b.r;
}
inline void add(int x){
--cnt2[cnt1[x]];
--tot[be[cnt1[x]]];
++cnt2[++cnt1[x]];
++tot[be[cnt1[x]]];
}
inline void del(int x){
--cnt2[cnt1[x]];
--tot[be[cnt1[x]]];
++cnt2[--cnt1[x]];
++tot[be[cnt1[x]]];
}
inline int get(int k){
int i;
for(i=1;i<=num;++i){
if(k-tot[i]<=0)break;
k-=tot[i];
}
if(i==num+1)return -1;
for(int j=L[i];j<=R[i];++j){
if(k-cnt2[j]<=0)return j;
k-=cnt2[j];
}
}
int main(){
scanf("%d%d",&n,&m);bl=pow(n,0.455);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
int tot=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
for(int i=1,tmp=-1;i<=n;++i){
be[i]=(i-1)/bl+1;
if(tmp^be[i])L[++num]=i,tmp=be[i];
R[num]=i;
}
for(int i=1;i<=m;++i){
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
for(int i=1,l=q[1].l,r=l-1;i<=m;++i){
while(l>q[i].l)add(a[--l]);
while(r<q[i].r)add(a[++r]);
while(l<q[i].l)del(a[l++]);
while(r>q[i].r)del(a[r--]);
ans[q[i].id]=get(q[i].k);
}
for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
return 0;
}