【分块】【树套树】bzoj2141 排队
考虑暴力更新的情况,设swap的是L,R位置的数。
swap之后的逆序对数应该等于:
之前的逆序对数
+[L+1,R-1]中比 L位置的数 大的数的个数
-[L+1,R-1]中比 L位置的数 小的数的个数
-[L+1,R-1]中比 R位置的数 大的数的个数
+[L+1,R-1]中比 R位置的数 小的数的个数
并且若L位置的数>R位置的数,逆序对数--;反之,逆序对数++。
分块,对每个块内部进行sort,这样可以二分,在O(log(sqrt(n))的时间内求得某个块内比某个数大/小的数的个数。所以每次更新是O(sqrt(n)*log(sqrt(n))的。
若L和R所在的块相同或相邻时,直接暴力更新即可。
要用树状数组或归并排序求得初始答案。
要注意数据是可重的,所以要打时间戳。
所以为了lower_bound/upper_bound,要定义两套比较法则,一套双关键字,一套单关键字。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 using namespace std; 5 struct Point{int v,p;Point(const int &a,const int &b){v=a;p=b;}Point(){}}; 6 bool operator < (const Point &a,const Point &b){return a.v<b.v;}//单关键字比较 7 bool operator > (const Point &a,const Point &b){return a.v>b.v;} 8 bool operator == (const Point &a,const Point &b){return a.v==b.v ? true : false;} 9 bool cmp(const Point &a,const Point &b){return a.v!=b.v ? a.v<b.v : a.p<b.p;}//双关键字比较 10 Point b[20001],a[20001],c[20001]; 11 int n,sz,l[145],r[145],sum,num[20001],ans,x,y,m,mid,en; 12 int Res,Num;char C,CH[20]; 13 inline int G() 14 { 15 Res=0;C='*'; 16 while(C<'0'||C>'9')C=getchar(); 17 while(C>='0'&&C<='9'){Res=Res*10+(C-'0');C=getchar();} 18 return Res; 19 } 20 inline void P(int x) 21 { 22 if(!x){putchar('0');putchar('\n');return;} 23 Num=0;while(x>0)CH[++Num]=x%10,x/=10; 24 while(Num)putchar(CH[Num--]+48); 25 putchar('\n'); 26 } 27 void LiSan() 28 { 29 n=G(); 30 for(int i=1;i<=n;i++){b[i].v=G();b[i].p=i;} 31 sort(b+1,b+n+1,cmp); 32 for(int i=1;i<=n;i++) 33 { 34 if(b[i].v!=b[i-1].v)en++; 35 a[b[i].p].v=en; 36 a[b[i].p].p=i; 37 } 38 } 39 //树状数组求出初始答案。 40 int D[20001];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].v,1);ans+=(i-getsum(a[i].v));} 45 P(ans);} 46 void makeblock() 47 { 48 sz=sqrt(n); 49 for(sum=1;sum*sz<n;sum++) 50 { 51 l[sum]=(sum-1)*sz+1;r[sum]=sum*sz; 52 for(int i=l[sum];i<=r[sum];i++) 53 num[i]=sum; 54 } 55 l[sum]=sz*(sum-1)+1;r[sum]=n; 56 for(int i=l[sum];i<=r[sum];i++) 57 num[i]=sum; 58 } 59 void Sort_Each_Block() 60 {for(int i=1;i<=n;i++)c[i]=a[i]; 61 for(int i=1;i<=sum;i++)sort(a+l[i],a+r[i]+1,cmp);} 62 inline int Query(const int &L,const int &R) 63 { 64 swap( a[lower_bound(a+l[num[L]],a+r[num[L]]+1,c[L],cmp) - a ] 65 , a[lower_bound(a+l[num[R]],a+r[num[R]]+1,c[R],cmp)- a ]);//必须双关键字比较 66 sort(a+l[num[L]],a+r[num[L]]+1,cmp); 67 sort(a+l[num[R]],a+r[num[R]]+1,cmp); 68 int cnt=0; 69 if(c[L].v<c[R].v)cnt=1; 70 else if(c[L].v>c[R].v)cnt=-1; 71 swap(c[L],c[R]); 72 if(num[L]+1>=num[R]) 73 for(int i=L+1;i<=R-1;i++) 74 {if(c[i].v>c[R].v)cnt++;else if(c[i].v<c[R].v)cnt--; 75 if(c[i].v>c[L].v)cnt--;else if(c[i].v<c[L].v)cnt++;} 76 else 77 { 78 for(int i=L+1;i<=r[num[L]];i++) 79 {if(c[i].v>c[R].v)cnt++;else if(c[i].v<c[R].v)cnt--; 80 if(c[i].v>c[L].v)cnt--;else if(c[i].v<c[L].v)cnt++;} 81 for(int i=l[num[R]];i<=R-1;i++) 82 {if(c[i].v>c[R].v)cnt++;else if(c[i].v<c[R].v)cnt--; 83 if(c[i].v>c[L].v)cnt--;else if(c[i].v<c[L].v)cnt++;} 84 for(int i=num[L]+1;i<=num[R]-1;i++) 85 { 86 cnt+=( (a+r[i]+1) - upper_bound(a+l[i],a+r[i]+1,c[R]) );//必须单关键字比较 87 cnt-=( lower_bound(a+l[i],a+r[i]+1,c[R]) - (a+l[i]) ); 88 cnt-=( (a+r[i]+1) - upper_bound(a+l[i],a+r[i]+1,c[L]) ); 89 cnt+=( lower_bound(a+l[i],a+r[i]+1,c[L]) - (a+l[i]) ); 90 } 91 } 92 ans+=cnt;return ans; 93 } 94 int main() 95 { 96 LiSan();Get_First_Ans();makeblock();Sort_Each_Block();m=G(); 97 for(int i=1;i<=m;i++){x=G();y=G();if(x>y)swap(x,y);P(Query(x,y));} 98 return 0; 99 }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/