luogu P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II
题面传送门
没有修改,考虑莫队,容易想到一个移动指针时用树状数组维护的\(O(n\sqrt nlogn)\)的方法,但是过不去。
这种情况就可以考虑莫队二次离线,把询问拆分,分类讨论一下即可。
注意这道题需要维护正反两个离线。注意卡常。注意离线那个树状数组要用域值分块来做到\(O(1)\)查询。
哦还有这道题有点问题,数组要开到\(2\times 10^5\)才能过。
代码实现:
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
int n,m,k,x,y,z,a[200039],l,r,mid,nows[200039],tots[200039];
int f[200039],fs[439],q1[200039],q2[200039];
long long ans[200039],tot[200039];
struct yyy{int x,y,flag,id;}tmp;
vector<yyy> g1[200039],g2[200039];
struct ques{int l,r,id;}s[200039],tmps;
inline void ls(int &x){for(l=0,r=n;l+1<r;)mid=l+r>>1,(nows[mid]<x)?(l=mid):(r=mid);x=tots[r];}
inline bool cmp(ques x,ques y){return x.l/k==y.l/k?(((x.l/k)&1)?x.r<y.r:x.r>y.r):x.l<y.l;}
inline void get1(int x){
register int i;
for(i=x/k+1;i<=n/k;i++) fs[i]++;
for(i=x;i<=x/k*k+k-1;i++) f[i]++;
}
inline void get2(int x){
register int i;
for(i=0;i<x/k;i++) fs[i]++;
for(i=x/k*k;i<=x;i++) f[i]++;
}
inline void clear(){memset(f,0,sizeof(f)),memset(fs,0,sizeof(fs));}
inline int find(int x){return fs[x/k]+f[x];}
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++)scanf("%d",&a[i]),nows[i]=a[i];
sort(nows+1,nows+n+1);
for(i=1;i<=n;i++) tots[i]=(i^1)?(tots[i-1]+(nows[i]!=nows[i-1])):1;
for(i=1;i<=n;i++) ls(a[i]);
for(i=1;i<=m;i++) scanf("%d%d",&x,&y),s[i]=(ques){x,y,i};
for(i=1;i<=n;i++)get2(a[i]),q1[i]=find(a[i]+1);clear();
for(i=n;i;i--) get1(a[i]),q2[i]=find(a[i]-1);clear();
sort(s+1,s+m+1,cmp);l=1;r=0;
for(i=1;i<=m;i++){
tmps=s[i];
if(r<tmps.r){
g1[l-1].push_back((yyy){r+1,tmps.r,-1,i});
while(r<tmps.r) ans[i]+=q1[++r];
}
if(r>tmps.r){
g1[l-1].push_back((yyy){tmps.r+1,r,1,i});
while(r>tmps.r) ans[i]-=q1[r--];
}
if(l>tmps.l){
g2[r+1].push_back((yyy){tmps.l,l-1,-1,i});
while(l>tmps.l) ans[i]+=q2[--l];
}
if(l<tmps.l){
g2[r+1].push_back((yyy){l,tmps.l-1,1,i});
while(l<tmps.l) ans[i]-=q2[l++];
}
}
for(i=1;i<=n;i++){
get2(a[i]);
for(j=0;j<g1[i].size();j++){
tmp=g1[i][j];
for(h=tmp.x;h<=tmp.y;h++) ans[tmp.id]+=find(a[h]+1)*tmp.flag;
}
}clear();
for(i=n;i;i--){
get1(a[i]);
for(j=0;j<g2[i].size();j++){
tmp=g2[i][j];
for(h=tmp.x;h<=tmp.y;h++) ans[tmp.id]+=find(a[h]-1)*tmp.flag;
}//printf("%d\n",i);
}
for(i=1;i<=m;i++) ans[i]+=ans[i-1],tot[s[i].id]=ans[i];
for(i=1;i<=m;i++) printf("%lld\n",tot[i]);
}