把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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]);
}
posted @ 2021-02-02 19:26  275307894a  阅读(73)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end