zoukankan      html  css  js  c++  java
  • 【洛谷5046】[Ynoi2019 模拟赛] Yuno loves sqrt technology I(分块)

    点此看题面

    • 给定一个长度为(n)的序列,(q)次询问区间逆序对个数。
    • (n,qle10^5),强制在线

    不同部分答案的拆解

    根据分块套路,一个询问区间肯定会被拆成一个后缀散块+中间一段整块+一个前缀散块。

    考虑不同部分答案的预处理与计算。

    中间一段整块内部的答案:可以直接预处理出(ans_{i,j})表示编号(isim j)的块的总答案。

    左边的后缀散块和右边的前缀散块内部的答案:可以分别预处理出(pre_i)(suf_i)表示(i)的前缀散块和后缀散块的答案。

    左右散块与中间整块间的答案:直接枚举散块中的元素,询问中间比它大/小的数的个数,只需开一个前缀和计数数组(c_{i,j})表示前(i)个块大于等于(j)的数的出现次数总和。

    左右散块间的答案:事先将每个块排好序,枚举左边块中的每个元素,双指针维护右边块中比左边当前元素小的元素并统计在询问区间内的元素个数,然后若左边当前元素在询问区间内就更新答案。

    还有一种情况就是询问的(l,r)在一个块中,此时可以用前缀散块(r)的答案减去前缀散块(l-1)的答案再减去这两部分间的答案。其中最后那家伙和上面左右散块间答案的求法类似,只不过由于在同一个块中可以不使用双指针,直接扫一遍即可。

    预处理还是比较简单的,(pre_i)(suf_i)只要利用树状数组,(c_{i,j})直接一遍后缀和+一遍前缀和,(ans_{i,j})就在(ans_{i,j-1})基础上加入(j)中的元素利用(c_{i,j})算贡献。

    代码:(O(nsqrt n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define SN 600
    #define LL long long
    using namespace std;
    int n,a[N+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    struct TreeArray
    {
    	int a[N+5];I void U(RI x,CI v) {W(x<=n) a[x]+=v,x+=x&-x;}
    	I int Q(RI x,RI t=0) {W(x) t+=a[x],x-=x&-x;return t;}
    }T;
    I bool cmp(CI x,CI y) {return a[x]<a[y];}//按值排序
    int p[N+5],v[N+5],pre[N+5],suf[N+5];I void Build(CI L,CI R)//预处理块[L,R]的信息
    {
    	RI i;for(i=L;i<=R;++i) p[i]=i,v[i]=a[i];sort(p+L,p+R+1,cmp),sort(v+L,v+R+1);//事先给每个块中元素排好序
    	for(i=R;i>=L;--i) suf[i]=(i^R?suf[i+1]:0)+T.Q(a[i]),T.U(a[i],1);for(i=L;i<=R;++i) T.U(a[i],-1);//预处理每个后缀散块内部答案
    	for(i=L;i<=R;++i) pre[i]=(i^L?pre[i-1]:0)+(i-L-T.Q(a[i])),T.U(a[i],1);for(i=L;i<=R;++i) T.U(a[i],-1);//预处理每个前缀散块内部答案
    }
    int sz,bl[N+5],pl[SN+5],pr[SN+5],c[SN+5][N+5];LL ans[SN+5][SN+5];I void Init()//预处理
    {
    	RI i,j,k;for(sz=280,i=1;i<=n;++i) ++c[bl[i]=(i-1)/sz+1][a[i]],!pl[bl[i]]&&(pl[bl[i]]=i),pr[bl[i]]=i;//记录每个元素所在块,记录每个块左右端点
    	for(i=1;i<=bl[n];++i) {for(Build(pl[i],pr[i]),j=n;j;--j) c[i][j]+=c[i][j+1];for(j=1;j<=n;++j) c[i][j]+=c[i-1][j];}//计数数组,一遍前缀和+一遍前缀和
    	for(i=1;i<=bl[n];++i) for(ans[i][i]=pre[pr[i]],j=i+1;j<=bl[n];++j)
    		for(ans[i][j]=ans[i][j-1]+pre[pr[j]],k=pl[j];k<=pr[j];++k) ans[i][j]+=c[j-1][a[k]]-c[i-1][a[k]];//在之前基础上加入当前块中元素
    }
    I LL Q(CI l,CI r)//询问区间逆序对个数
    {
    	RI i,t=0,s=0,L=bl[l],R=bl[r];if(L==R)//同块
    	{
    		if(l==pl[L]) return pre[r];s=pre[r]-pre[l-1];for(i=pl[L];i<=pr[L];++i) p[i]<l?s-=t:p[i]<=r&&++t;return s;//直接扫一遍
    	}
    	int *c1=c[L],*c2=c[R-1];s=(pr[L]-l+1)*(R-L-1)*sz;
    	for(i=l;i<=pr[L];++i) s-=c2[a[i]]-c1[a[i]];for(i=pl[R];i<=r;++i) s+=c2[a[i]]-c1[a[i]];//散块与整块
    	int *PL=p+pl[L],*VL=v+pl[L],*EL=v+pr[L]+1,*PR=p+pl[R],*VR=v+pl[R],*ER=v+pr[R]+1;
    	for(;VL!=EL;*PL>=l&&(s+=t),++PL,++VL) W(VR!=ER&&*VL>*VR) *PR<=r&&++t,++PR,++VR;//散块与散块(双指针)
    	return suf[l]+ans[L+1][R-1]+pre[r]+s;//加上三部分各自的内部答案
    }
    int main()
    {
    	RI Qt,i;for(read(n,Qt),i=1;i<=n;++i) read(a[i]);
    	LL l,r,lst=0;Init();W(Qt--) read(l,r),writeln(lst=Q(l^lst,r^lst));return clear(),0;//强制在线
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Leetcode Reverse Words in a String
    topcoder SRM 619 DIV2 GoodCompanyDivTwo
    topcoder SRM 618 DIV2 MovingRooksDiv2
    topcoder SRM 618 DIV2 WritingWords
    topcoder SRM 618 DIV2 LongWordsDiv2
    Zepto Code Rush 2014 A. Feed with Candy
    Zepto Code Rush 2014 B
    Codeforces Round #245 (Div. 2) B
    Codeforces Round #245 (Div. 2) A
    Codeforces Round #247 (Div. 2) B
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5046.html
Copyright © 2011-2022 走看看