【Ynoi2019】Yuno loves sqrt technology I

【Ynoi2019】Yuno loves sqrt technology I

by AmanoKumiko

Description

给出长为\(n\)的排列,有\(m\)次询问

每次询问一个区间的逆序对数

强制在线

Input

第一行两个数\(n,m\)

然后一行\(n\)个数读入排列

Output

一共\(m\)行,每行一个数表示答案

Sample Input

4 1
1 4 2 3
2 4

Sample Output

2

Data Constraint

\(1\le n,m\le 10^5\)

Solution

非常精妙地运用了归并思想

对序列分块,先把贡献拆开

1.块与块

\(f_{i,j}\)表示第\(i\)到第\(j\)块的贡献

可以写成\(f_{i,j}=f_{i+1,j}+f_{i,j-1}-f_{i+1,j-1}+S(i,j)\)(这个也太妙了吧

\(S(i,j)\)即第\(i\)和第\(j\)块产生的贡献

2.点与块

\(cnt_{i,j}\)表示前\(i\)块中\(\ge j\)的数的个数,可以\(O(n\sqrt n)\)预处理

\(pre_i,suf_i\)分别表示一段前缀和后缀的贡献,扫一遍就行了

3.点与点

直接归并

PS:这题也太卡了吧。。。

Code

#include<bits/stdc++.h>
using namespace std;
#define Fo(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define N 100010
#define M 650
inline char gc()
{
	static char buf[1048576],*p1,*p2;
 	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1048576,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
	char ch=gc();int r=0,w=1;
	for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
	for(;'0'<=ch&&ch<='9';ch=gc())r=r*10+(ch-'0');
	return r*w;
}
namespace IO{
	const int sz=1<<22;
	char b[sz+5],*t=b,p[105];
	inline void flush(){fwrite(b,1,t-b,stdout),t=b;}
	inline void pc(char x){*t++=x;if(t-b==sz)flush();}
	template<class T>void write(T x,char c='\n'){
		if(x==0)pc('0');int t=0;
		for(;x;x/=10)p[++t]=x%10+'0';
		for(;t;--t)pc(p[t]);pc(c);
	}
	struct F{~F(){flush();}}f;
}
using IO::write;

int ql[N],qr[N],tl,tr;
int n,m,a[N],b[M][M],pre[N],suf[N],cnt[M][N],tmp[N],B,sz,L[M],R[M],be[N],len[M],pos[N];
LL ans,f[M][M];
struct tree{
	int sum[N];
	int lowbit(int x){return -x&x;}
	void modify(int x,int y){while(x<=n)sum[x]+=y,x+=lowbit(x);}
	int qur(int x){int res=0;while(x)res+=sum[x],x-=lowbit(x);return res;}
}t;

int main(){
	n=read();m=read();
	Fo(i,1,n)pos[a[i]=read()]=i;
	B=160;
	sz=n/B+1;
	Fo(i,1,sz){
		L[i]=R[i-1]+1;R[i]=min(n,L[i]+B-1);
		len[i]=R[i]-L[i]+1;
		if(len[i]<=0)continue;
		Fo(j,L[i],R[i])b[i][j-L[i]+1]=a[j],be[j]=i,tmp[a[j]]++;
		sort(b[i]+1,b[i]+len[i]+1);
		Fo(j,L[i],R[i]){
			pre[j]=(j-1>=L[i]?pre[j-1]:0);
			pre[j]+=j-L[i]-t.qur(a[j]);
			t.modify(a[j],1);
		}
		int nw=pre[R[i]];
		Fo(j,L[i],R[i]){
			t.modify(a[j],-1);
			suf[j]=nw;nw-=t.qur(a[j]);
		}
		Fd(j,n,1)tmp[j]+=tmp[j+1];
		Fo(j,1,n)cnt[i][j]=cnt[i-1][j]+tmp[j],tmp[j]=0;
	}
	Fd(i,sz,1){
		f[i][i]=pre[R[i]];
		Fo(j,i+1,sz){
			f[i][j]=f[i+1][j]+f[i][j-1]-f[i+1][j-1];
			int t=1;
			Fo(k,1,len[j]){while(b[i][t]<=b[j][k]&&t<=len[i])t++;f[i][j]+=len[i]-t+1;}
		}
	}
	Fo(i,1,m){
		int l=read(),r=read();
		l^=ans;r^=ans;
		if(be[l]==be[r]){
			if(l==L[be[l]]){ans=pre[r];write(ans);continue;}
			ans=pre[r]-pre[l-1];
			tl=tr=0;
			Fo(j,1,len[be[l]]){
				if(pos[b[be[l]][j]]<=l-1)ql[++tl]=b[be[l]][j];
				else if(pos[b[be[l]][j]]<=r)qr[++tr]=b[be[l]][j];
			}
			int t=1;
			Fo(j,1,tr){while(ql[t]<=qr[j]&&t<=tl)t++;ans-=tl-t+1;}
			write(ans);
		}else{
			ans=f[be[l]+1][be[r]-1]+suf[l]+pre[r]+1ll*(R[be[l]]-l+1)*(R[be[r]-1]-L[be[l]+1]+1);
			Fo(j,l,R[be[l]])ans-=cnt[be[r]-1][a[j]]-cnt[be[l]][a[j]];
			Fo(j,L[be[r]],r)ans+=cnt[be[r]-1][a[j]+1]-cnt[be[l]][a[j]+1];
			int wz=1,nw=0,nw1=0;
			Fo(j,1,len[be[l]])if(pos[b[be[l]][j]]>=l)
			{
				while(wz<=len[be[r]]&&b[be[r]][wz]<b[be[l]][j])nw+=(pos[b[be[r]][wz]]<=r),wz++;
				if(nw==r-L[be[r]]+1)
				{
					ans+=nw*(R[be[l]]-l+1-nw1);
					break;
				}
				ans+=nw;nw1++;
			}
			write(ans);
		}
	}
	return 0;
}
posted @ 2022-08-06 08:21  冰雾  阅读(35)  评论(0编辑  收藏  举报