每n^2/3个数分一块,然后预处理从第i块到第j块前k个数的答案以及第k个数有多少个
然后查询的时候同块暴力,不同块的话中间调用答案,两边零散的调用已经有多少个数来更新答案
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 50010
#define MAXM 20010
#define MAXS 40
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
int n,m,q;
int a[MAXN];
int c[MAXS][MAXS][MAXM];
int C[MAXN],vis[MAXN];
int T;
ll ans[MAXS][MAXS][MAXM];
int bel[MAXN];
int siz;
int st[MAXN],ed[MAXN];
ll la;
ll ask(int l,int r,int x,int y){
int i;
ll re=0;
T++;
if(bel[l]==bel[r]){
for(i=l;i<=r;i++){
if(a[i]>=x&&a[i]<=y){
if(vis[a[i]]!=T){
C[a[i]]=0;
vis[a[i]]=T;
}
re+=C[a[i]]*2+1;
C[a[i]]++;
}
}
}else{
re=ans[bel[l]+1][bel[r]-1][y]-ans[bel[l]+1][bel[r]-1][x-1];
for(i=l;i<=ed[bel[l]];i++){
if(a[i]>=x&&a[i]<=y){
if(vis[a[i]]!=T){
C[a[i]]=c[bel[l]+1][bel[r]-1][a[i]];
vis[a[i]]=T;
}
re+=C[a[i]]*2+1;
C[a[i]]++;
}
}
for(i=r;i>=st[bel[r]];i--){
if(a[i]>=x&&a[i]<=y){
if(vis[a[i]]!=T){
C[a[i]]=c[bel[l]+1][bel[r]-1][a[i]];
vis[a[i]]=T;
}
re+=C[a[i]]*2+1;
C[a[i]]++;
}
}
}
return re;
}
int main(){
freopen("data.txt","r",stdin);
int i,j,k;
ll l,r,x,y;
scanf("%d%d%d",&n,&m,&q);
siz=int(ceil(pow(n,2.0/3)));
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
bel[i]=(i-1)/siz+1;
if(!st[bel[i]]){
st[bel[i]]=i;
}
ed[bel[i]]=i;
}
for(i=1;i<=bel[n];i++){
for(j=i;j<=bel[n];j++){
for(k=st[i];k<=ed[j];k++){
c[i][j][a[k]]++;
}
}
}
for(i=1;i<=bel[n];i++){
for(j=i;j<=bel[n];j++){
for(k=1;k<=m;k++){
ans[i][j][k]=ans[i][j][k-1]+(ll)c[i][j][k]*c[i][j][k];
}
}
}
while(q--){
scanf("%lld%lld%lld%lld",&l,&r,&x,&y);
l^=la;
r^=la;
x^=la;
y^=la;
printf("%lld\n",la=ask(int(l),int(r),int(x),int(y)));
}
return 0;
}
/*
4 2 3
1 1 2 2
1 4 1 2
10 11 9 10
3 0 0 0
*/

博客探讨了如何使用颜色分块策略进行数的预处理,以便快速查询第i块到第j块前k个数的答案,并计算第k个数的数量。在查询时,同块采用暴力方法,不同块则结合预处理信息进行高效计算。
1335

被折叠的 条评论
为什么被折叠?



