根号 log 做法。能过 CF 的数据,但过不了校内模拟赛的数据/tuu
考虑从 \(f(i,x)\) 到 \(f(i+1,x)\) 的变化在哪里:少了个 \(a_i\) 多了个 \(a_{i+m}\),因此显然只有 \(x\) 在它俩中间才有 \(f(i,x)\ne f(i+1,x)\),即:
\[f(i+1,x)-f(i,x)=\begin{cases}-1&(a_i<x\le a_{i+m})\\1&(a_{i+m}<x\le a_i)\\0&\text{otherwise}\end{cases} \]我们不妨记其为 \(g(i,x)\)。换句话说这个 \(g(i,x)\) 的贡献形式是一段区间。
而显然 \(f(j,x)=f(i,x)+\sum\limits_{k=i}^{j-1}g(k,x)\),因此询问等价于查询 \(f(l,x)\) 和 \(g(l,x),g(l+1,x),\cdots,g(r-1,x)\) 的最小前缀和。由于空间 64MB(一眼沙东 OI problemprovidercreep),考虑分块,对于前者直接将区间中的数排个序 lower_bound 即可,对于后者将这个块内所有区间左右端点当作关键点离散化,然后对每一段分别求出 \(x\) 在这一段内的最小前缀和和总和即可。块长取 \(\sqrt{n\log n}\) 时最优。
const int MAXN=2e5;
const int BLK_SZ=900;
const int BLK_CNT=MAXN/BLK_SZ;
int n,m,typ,a[MAXN+5],b[MAXN+5],L[MAXN+5],R[MAXN+5],blk_sz,blk_cnt,bel[MAXN+5];
int calc_less(int l,int r,int x){
if(bel[l]==bel[r]){
int sum=0;
for(int i=l;i<=r;i++)sum+=(a[i]<x);
return sum;
}else{
int sum=0;
for(int i=l;i<=R[bel[l]];i++)sum+=(a[i]<x);
for(int i=L[bel[r]];i<=r;i++)sum+=(a[i]<x);
for(int i=bel[l]+1;i<bel[r];i++){
int pos=lower_bound(b+L[i],b+R[i]+1,x)-b;
sum+=pos-L[i];
}return sum;
}
}
tuple<int,int,int>c[MAXN+5];
int key[BLK_CNT+5][BLK_SZ*2+5],uni[BLK_CNT+5][BLK_SZ*2+5];
int cnt[BLK_SZ+5],num[BLK_SZ+5];
int sum[BLK_CNT+5][BLK_SZ*2+5],mn[BLK_CNT+5][BLK_SZ*2+5];
int calc_mn(int l,int r,int x){
if(bel[l]==bel[r]){
int _sum=0,_mn=0;
for(int i=l;i<=r;i++){
if(get<0>(c[i])<=x&&x<=get<1>(c[i]))_sum+=get<2>(c[i]);
chkmin(_mn,_sum);
}return _mn;
}else{
int _sum=0,_mn=0;
for(int i=l;i<=R[bel[l]];i++){
if(get<0>(c[i])<=x&&x<=get<1>(c[i]))_sum+=get<2>(c[i]);
chkmin(_mn,_sum);
}
for(int i=bel[l]+1;i<bel[r];i++){
int pos=upper_bound(uni[i]+1,uni[i]+num[i]+1,x)-uni[i]-1;
chkmin(_mn,_sum+mn[i][pos]);_sum+=sum[i][pos];
}
for(int i=L[bel[r]];i<=r;i++){
if(get<0>(c[i])<=x&&x<=get<1>(c[i]))_sum+=get<2>(c[i]);
chkmin(_mn,_sum);
}
return _mn;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
blk_sz=BLK_SZ;blk_cnt=(n-1)/blk_sz+1;
for(int i=1;i<=blk_cnt;i++){
L[i]=(i-1)*blk_sz+1;R[i]=min(i*blk_sz,n);
for(int j=L[i];j<=R[i];j++)bel[j]=i;
}
for(int i=1;i<=blk_cnt;i++)sort(b+L[i],b+R[i]+1);
for(int i=1;i<=n-m;i++){
if(a[i]<a[i+m])c[i]=mt(a[i]+1,a[i+m],-1);
else if(a[i]>a[i+m])c[i]=mt(a[i+m]+1,a[i],1);
}
for(int i=1;i<=blk_cnt;i++){
for(int j=L[i];j<=R[i];j++)if(get<2>(c[j]))
key[i][++cnt[i]]=get<0>(c[j]),key[i][++cnt[i]]=get<1>(c[j])+1;
key[i][++cnt[i]]=0;
sort(key[i]+1,key[i]+cnt[i]+1);key[i][0]=-1;
for(int j=1;j<=cnt[i];j++)if(key[i][j]!=key[i][j-1])uni[i][++num[i]]=key[i][j];
for(int j=1;j<=num[i];j++){
int SUM=0,MN=0;
for(int k=L[i];k<=R[i];k++){
if(get<0>(c[k])<=uni[i][j]&&uni[i][j]<=get<1>(c[k]))
SUM+=get<2>(c[k]);
chkmin(MN,SUM);
}mn[i][j]=MN;sum[i][j]=SUM;
}
}
int qu,lstans=0;scanf("%d",&qu);
while(qu--){
int l,r,x;scanf("%d%d%d",&l,&r,&x);x^=lstans;
if(l==r)printf("%d\n",lstans=calc_less(l,l+m-1,x));
else printf("%d\n",lstans=calc_less(l,l+m-1,x)+calc_mn(l,r-1,x));
}
return 0;
}
标签:SZ,Listening,int,sum,mn,Codeforces,Music,BLK,MAXN
From: https://www.cnblogs.com/tzcwk/p/Codeforces-543E.html