2018目标:让 nzhtl1477 打通罚抄!
这题其实不难写,就是我写完后 MLE 了。。。
对权值和序列都分块,假设 n 和值域同阶
记
记
c[i][j]
表示前
i
块,权值为
预处理这个是 O(nn√)
对于查询:直接暴力每块, O(n√)
对于修改:
两边的块暴力重构。
中间的块:如果没有
x
跳出;如果没有
注意:暴力重构只会更新
b,c
中
x,y
有关的下标,所以修改
b,c
复杂度
O(n√)
。
总复杂度
O(nn√)
具体实现时,对于每块记一个
id[x]
和
fid[x]
表示
x
对应的
#include<bits/stdc++.h>
#define maxn 100100
#define BLK 320
#define LK(x) ((x)*kuai)
#define RK(x) min(((x)+1)*kuai,n)
using namespace std;
int kuai,a[maxn],n,Q,_m,mkuai,cnt[BLK][maxn];
int b[BLK][1000],h[BLK][maxn],fh[BLK][1000],ls[maxn],ls2[2000],c[maxn];
void pd(int id){
int l=LK(id),r=RK(id);
// printf("\n<%d,%d>",l,r-1);
for(int i=l;i<r;++i)
a[i]=fh[id][c[i]];
}
void change(int bl,int x,int y){
int id=h[bl][x];
h[bl][y]=id,h[bl][x]=0,fh[bl][id]=y;
}
void build(int id){
int tp=0;
int l=LK(id),r=RK(id);
for(int i=1;i<=kuai;++i)h[id][fh[id][i]]=0;
for(int i=l;i<r;++i)if(!h[id][a[i]])
h[id][a[i]]=++tp,fh[id][tp]=a[i];
for(int i=l;i<r;++i)
c[i]=h[id][a[i]];
}
int main(){
// freopen("data2.in","r",stdin);
// freopen("out.txt","w",stdout);
int M=100100;
scanf("%d%d",&n,&Q);
// Q=20;
kuai=500;//sqrt(n)+1;
mkuai=500;
int m=n/kuai+1,_m=M/mkuai+1;
for(int i=0;i<n;++i)
scanf("%d",&a[i]);
for(int i=0;i<m;++i){
for(int j=LK(i),tp=0;j<RK(i);++j)if(!h[i][a[j]])
h[i][a[j]]=++tp,fh[i][tp]=a[j];
for(int j=LK(i),tp=0;j<RK(i);++j)
c[j]=h[i][a[j]];
}
for(int i=0;i<m;++i){
if(i)for(int j=0;j<M;++j)
cnt[i][j]=cnt[i-1][j];
if(i)for(int j=0;j<_m;++j)
b[i][j]=b[i-1][j];
for(int j=LK(i);j<RK(i);++j)
cnt[i][a[j]]++,b[i][a[j]/mkuai]++;
}
for(int ni=1,op,l,r,x,y;ni<=Q;++ni){
scanf("%d%d%d",&op,&l,&r);
l--,r--;
if(op==1){
scanf("%d%d",&x,&y);
// printf("{%d,%d,%d,%d}\n",l,r,x,y);
int bl=l/kuai,br=r/kuai;
int bx=x/mkuai,by=y/mkuai;
if(cnt[br][x]-(bl?cnt[bl-1][x]:0)==0)continue;
for(int i=m-1;i>=1&&i>=bl;--i)
cnt[i][x]-=cnt[i-1][x],cnt[i][y]-=cnt[i-1][y],
b[i][bx]-=b[i-1][bx],b[i][by]-=b[i-1][by];
if(bl==br){
pd(bl);
for(int i=l;i<=r;++i)
if(a[i]==x)a[i]=y,cnt[bl][x]--,cnt[bl][y]++,b[bl][bx]--,b[bl][by]++;
build(bl);
} else {
pd(bl),pd(br);
for(int i=l;i<RK(bl);++i)
if(a[i]==x)a[i]=y,cnt[bl][x]--,cnt[bl][y]++,b[bl][bx]--,b[bl][by]++;
for(int i=LK(br);i<=r;++i)
if(a[i]==x)a[i]=y,cnt[br][x]--,cnt[br][y]++,b[br][bx]--,b[br][by]++;
build(bl),build(br);
for(int i=bl+1;i<br;++i)if(cnt[i][x]){
if(cnt[i][y]){
pd(i);
for(int j=LK(i);j<RK(i);++j)
if(a[j]==x)a[j]=y,cnt[i][x]--,cnt[i][y]++,b[i][bx]--,b[i][by]++;
build(i);
} else {
b[i][by]+=cnt[i][x];
b[i][bx]-=cnt[i][x];
cnt[i][y]+=cnt[i][x],cnt[i][x]=0;
change(i,x,y);
}
}
}
for(int i=max(1,bl);i<m;++i)
cnt[i][x]+=cnt[i-1][x],cnt[i][y]+=cnt[i-1][y],
b[i][bx]+=b[i-1][bx],b[i][by]+=b[i-1][by];
} else {
scanf("%d",&x);
int bl=l/kuai,br=r/kuai;
if(bl==br){
pd(bl);
for(int i=l;i<=r;++i)ls[i]=a[i];
nth_element(ls+l,ls+l+x-1,ls+r+1);
printf("%d\n",ls[l+x-1]);
for(int i=l;i<=r;++i)ls[i]=0;
} else {
pd(bl),pd(br);
for(int i=l;i<RK(bl);++i)ls[a[i]]++,ls2[a[i]/mkuai]++;//,printf("{%d}",a[i]);
for(int i=LK(br);i<=r;++i)ls[a[i]]++,ls2[a[i]/mkuai]++;//,printf("{%d}>",a[i]);
for(int i=0,sum=0;i<_m;++i)
if(ls2[i]+b[br-1][i]-b[bl][i]+sum>=x){
for(int j=i*mkuai;j<(i+1)*mkuai;++j){
if(ls[j]+cnt[br-1][j]-cnt[bl][j]+sum>=x){
printf("%d\n",j);
goto lxldl;
} else sum+=ls[j]+cnt[br-1][j]-cnt[bl][j];
}
} else sum+=ls2[i]+b[br-1][i]-b[bl][i];
lxldl:
for(int i=l;i<RK(bl);++i)ls[a[i]]--,ls2[a[i]/mkuai]--;
for(int i=LK(br);i<=r;++i)ls[a[i]]--,ls2[a[i]/mkuai]--;
}
}
}
}