luogu P4867 Gty的二逼妹子序列
题面传送门
空间这么小,只能莫队。在移动时用域值分块\(O(1)\)修改即可。
代码实现:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,k,x,y,z,ans[1000039],a[100039],l,r,mid,f[100039],ku[100039],st[100039];
struct yyy{int x,y,a,b,num;}fs[1000039],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();
}
inline void print(int x){
if(x>9) print(x/10);
putchar(x%10+48);
}
int main(){
register int i,j,l=1,r=0;
register yyy tmp;
read(n);read(m);
k=sqrt(n);
for(i=1;i<=n;i++) read(a[i]);
for(i=1;i<=m;i++) read(fs[i].x),read(fs[i].y),read(fs[i].a),read(fs[i].b),fs[i].num=i;
sort(fs+1,fs+m+1,cmp);
l=1;
for(i=1;i<=m;i++){
tmp=fs[i];
while(l>tmp.x){
l--;
f[a[l]]++;
if(f[a[l]]==1) st[a[l]]=1,ku[a[l]/k]++;
}
while(r<tmp.y){
r++;
f[a[r]]++;
if(f[a[r]]==1) st[a[r]]=1,ku[a[r]/k]++;
}
while(l<tmp.x){
if(f[a[l]]==1) st[a[l]]=0,ku[a[l]/k]--;
f[a[l]]--;
l++;
}
while(r>tmp.y){
if(f[a[r]]==1) st[a[r]]=0,ku[a[r]/k]--;
f[a[r]]--;
r--;
}
if(tmp.a/k==tmp.b/k) for(j=tmp.a;j<=tmp.b;j++) ans[tmp.num]+=st[j];
else {
for(j=tmp.a;j<tmp.a/k*k+k;j++) ans[tmp.num]+=st[j];
for(j=tmp.a/k+1;j<tmp.b/k;j++) ans[tmp.num]+=ku[j];
for(j=tmp.b/k*k;j<=tmp.b;j++) ans[tmp.num]+=st[j];
}
}
for(i=1;i<=m;i++) print(ans[i]),putchar('\n');
}