首页 > 代码库 > 【分块】bzoj3295 [Cqoi2011]动态逆序对

【分块】bzoj3295 [Cqoi2011]动态逆序对

考虑每次删除pos位置一个数x后,所造成的的影响就是,逆序对的个数少了在1~pos-1中大于x的数的个数加上pos+1~n中小于x的数的个数。

那么我们需要的操作就只有查询区间内比某数大(小)的个数。

↑,分块经典操作,每个块里维护一个有序表。

由于有删除,最好每个块用一个vector。

对于原数列怎么办呢?只需要弄一个vis数组,vis[i]表示i位置的数已经删除即可。(要找到v在原数列中的位置的话,在其所在块暴力即可。)

查询时对整块二分,对要删的元素所在块分成两段暴力。

O(n*sqrt(n)*log2(sqrt(n)))

【觉得我已经丧心病狂了,bzoj的树套树题只会用分块水怎么办啊,一旦不是总时限不就T了吗……QAQ】

P.S.请用long long。

 1 #include<cstdio> 2 #include<vector> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 bool vis[100001]; 7 int n,m,a[100001],sum,num[100001],sz,l[400],r[400],v; 8 long long ans; 9 vector<int>b[400];10 vector<int>::iterator it;11 int Res,Num;char C,CH[12];12 inline int G()13 {14     Res=0;C=*; 15     while(C<0||C>9)C=getchar();16     while(C>=0&&C<=9){Res=Res*10+(C-0);C=getchar();}17     return Res;18 }19 inline void P(long long x)20 {21     Num=0;if(!x){putchar(0);puts("");return;}22     while(x>0)CH[++Num]=x%10,x/=10;23     while(Num)putchar(CH[Num--]+48);24     puts("");25 }26 void makeblock()27 {28     sz=sqrt((double)n*log2(n));29     for(sum=1;sum*sz<n;sum++)30       {31         l[sum]=(sum-1)*sz+1;32         r[sum]=sum*sz;33         for(int i=l[sum];i<=r[sum];i++) num[i]=sum,b[sum].push_back(a[i]);34         sort(b[sum].begin(),b[sum].end());35       }36     l[sum]=sz*(sum-1)+1; r[sum]=n;37     for(int i=l[sum];i<=r[sum];i++) {num[i]=sum; b[sum].push_back(a[i]);}38     sort(b[sum].begin(),b[sum].end());39 }40 int D[100001];inline int lowbit(const int &x){return x&(-x);}41 inline int getsum(int x){int res=0;while(x>0){res+=D[x];x-=lowbit(x);}return res;}42 inline void add(int x,const int &d){while(x<=n){D[x]+=d;x+=lowbit(x);}}43 void Get_First_Ans()44 {for(int i=1;i<=n;i++){add(a[i],1);ans+=(long long)i-getsum(a[i]);}}45 int Get_Pos(const int &v,const int &L,const int &R)46 {for(int i=L;i<=R;i++) if(!vis[i] && a[i]==v) return i;}47 void update()48 {49     for(int i=1;i<=sum;i++)50       {51         it=lower_bound(b[i].begin(),b[i].end(),v);52         if(*it==v)53           {54             int p=Get_Pos(v,l[i],r[i]); vis[p]=true;55             for(int j=1;j<i;j++) ans-=(long long)(b[j].end()-upper_bound(b[j].begin(),b[j].end(),v));56             for(int j=l[i];j<p;j++) if(!vis[j] && a[j]>v) ans--;57             for(int j=i+1;j<=sum;j++) ans-=(long long)(lower_bound(b[j].begin(),b[j].end(),v)-b[j].begin());58             for(int j=p+1;j<=r[i];j++) if(!vis[j] && a[j]<v) ans--;59             b[i].erase(it);60             break;61           }62       }63 }64 int main()65 {66     n=G();m=G();67     for(int i=1;i<=n;i++) a[i]=G();68     Get_First_Ans();69     makeblock();70     for(int i=1;i<=m;i++)71       {72         v=G(); P(ans);73         update();74       }75     return 0;76 }

 

【分块】bzoj3295 [Cqoi2011]动态逆序对