luogu P3730 曼哈顿交易
题面传送门
显然可以莫队,而且是板子题。
但是考虑怎么在过程中增加和修改,无论怎样写树形结构都会使复杂度飙升到\(n\sqrt nlogn\)
这时可以暴力数据结构:分块,单点修改\(O(1)\),查询\(O(\sqrt n)\)
这样复杂度就是妥妥的\(O(n\sqrt n)\)
代码实现:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,k,x,y,z,nows[100039],tots[100039],a[100039],l,r,mid,ans[100039],st[100039],fs[100039],ku[1039];
struct yyy{int x,y,z,num;}f[100039],tmp;
inline bool cmp(yyy x,yyy y){return ((x.x/k==y.x/k)?(((x.x/k)&1)?x.y<y.y:x.y>y.y):x.x<y.x);}
inline void read(int &x){
char s=getchar();x=0;
while(s<'0'||s>'9') s=getchar();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
register int i,j,h;
scanf("%d%d",&n,&m);
k=sqrt(n);
for(i=1;i<=n;i++) read(a[i]),nows[i]=a[i];
for(i=1;i<=m;i++) read(f[i].x),read(f[i].y),read(f[i].z),f[i].num=i;
sort(nows+1,nows+n+1);
for(i=1;i<=n;i++){
tots[i]=tots[i-1];
if(nows[i]!=nows[i-1]) tots[i]++;
}
for(i=1;i<=n;i++){
l=0;r=n+1;
while(l+1<r){
mid=(l+r)>>1;
if(nows[mid]<a[i]) l=mid;
else r=mid;
}
a[i]=tots[r];
}
sort(f+1,f+m+1,cmp);
l=1;r=0;
for(i=1;i<=m;i++){
tmp=f[i];
while(l>tmp.x){
l--;
if(st[a[l]])ku[st[a[l]]/k]--,fs[st[a[l]]]--;
st[a[l]]++;
fs[st[a[l]]]++;
ku[st[a[l]]/k]++;
}
while(r<tmp.y){
r++;
if(st[a[r]])ku[st[a[r]]/k]--,fs[st[a[r]]]--;
st[a[r]]++;
fs[st[a[r]]]++;
ku[st[a[r]]/k]++;
//printf("%d %d %d\n",r,fs[st[a[r]]],ku[st[a[r]]/k]);
}
while(l<tmp.x){
ku[st[a[l]]/k]--;
fs[st[a[l]]]--;
st[a[l]]--;
if(st[a[l]])fs[st[a[l]]]++,ku[st[a[l]]/k]++;
l++;
}
while(r>tmp.y){
ku[st[a[r]]/k]--;
fs[st[a[r]]]--;
st[a[r]]--;
if(st[a[r]])fs[st[a[r]]]++,ku[st[a[r]]/k]++;
r--;
}
ans[tmp.num]=-1;
for(j=0;j<=n/k;j++){
//printf("%d\n",fs[0]);
if(tmp.z>ku[j]) tmp.z-=ku[j];
else{
for(h=j*k;h<j*k+k;h++) {
if(tmp.z>fs[h]) tmp.z-=fs[h];
else {ans[tmp.num]=h;break;}
}
break;
}
}
}
for(i=1;i<=m;i++) printf("%d\n",ans[i]);
}