Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
HINT
N<=100000 M<=50000
思路
最近一直都在做一些树套树的题目呢=。=
求解逆序对有两种方法,树状数组和归并排序,前者一般来说优于后者。。而且好写太多了。
首先算出最初的答案ans,和一个数的左边比它大的数以及右边比它小的数的个数。
每次删除一个数之后,ans就减去左边比他大以及右边比他小的数的个数。
然而前面删除的时候有可能会对后面产生影响,于是我们维护在[l,r]范围内被删除的比I小的数的个数,那么就用树状数组套线段树组成。
外层树状数组记录权值,内层线段树记录位置,为了节省空间,线段树动态开点(要不然二维树状数组不就好了么。。)
一开始我没有记录最开始一个数的左边比它大的数以及右边比它小的数的个数,而是动态维护,导致线段树疯狂开点,怒E。。
一次查询最多只会涉及到Log2n个节点(树状数组Logn次查询*每次查询Logn个节点),于是总共的空间是mLog2n的,完全可以接受。
如果直接动态维护一个数的左边比它大的数以及右边比它小的数的个数的话空间复杂度是O(n2)的,Terrible。。
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <cmath> 7 #include <algorithm> 8 #include <queue> 9 #include <stack> 10 #include <map> 11 #include <set> 12 #include <list> 13 #include <vector> 14 #include <ctime> 15 #include <functional> 16 #define pritnf printf 17 #define scafn scanf 18 #define sacnf scanf 19 #define For(i,j,k) for(int i=(j);i<=(k);(i)++) 20 #define Clear(a) memset(a,0,sizeof(a)) 21 using namespace std; 22 typedef unsigned int Uint; 23 const int INF=0x3fffffff; 24 ///==============struct declaration============== 25 struct Seg_Node{ 26 Seg_Node *lc,*rc; 27 int addv; 28 long long sum; 29 Seg_Node (){lc=rc=NULL;sum=0;addv=0;} 30 }; 31 ///==============var declaration================= 32 const int MAXN=100050; 33 int n,L,R,k,v,m; 34 long long ans=0; 35 Seg_Node *BitTree[MAXN]; 36 int A[MAXN],Index[MAXN],Prefix[MAXN]; 37 int LeftGreater[MAXN],RightLess[MAXN],Bit[MAXN]; 38 ///==============function declaration============ 39 void Add_Bit(int x); 40 void Add_Prefix(int x,int val); 41 int lowbit(int x){return x&-x;} 42 int Query_Prefix(int x); 43 long long Query_Bit(int x); 44 void Add_Seg(Seg_Node *&Node,int l,int r); 45 long long Query_Seg(Seg_Node *&Node,int l,int r,int add); 46 void update(Seg_Node *&Node,int l,int r); 47 inline void qread(int &x); 48 void Add_Bit(int *P,int x); 49 int Query_Bit(int *P,int x); 50 ///==============main code======================= 51 int main() 52 { 53 //#define FILE__ 54 #ifdef FILE__ 55 freopen("input.txt","r",stdin); 56 freopen("output.txt","w",stdout); 57 #endif 58 scanf("%d%d",&n,&m); 59 for(int i=1;i<=n;i++){ 60 qread(A[i]); 61 Index[A[i]]=i;k=i;v=1; 62 Add_Prefix(i,1);Add_Bit(Bit,A[i]); 63 LeftGreater[i]=i-Query_Bit(Bit,A[i]); 64 ans+=LeftGreater[i]; 65 } 66 memset(Bit,0,sizeof(Bit)); 67 for(int i=n;i>=1;i--){ 68 Add_Bit(Bit,A[i]); 69 RightLess[i]=Query_Bit(Bit,A[i]-1); 70 } 71 while (m--){ 72 int num,pos;qread(num);pos=Index[num]; 73 printf("%lld ",ans); 74 int Left=0,Right=0; 75 ans-=LeftGreater[pos]+RightLess[pos]; 76 L=1,R=pos-1; 77 if (L<=R) 78 Left=Query_Bit(n)-Query_Bit(num); 79 L=pos+1,R=n; 80 if (L<=R) 81 Right=Query_Bit(num); 82 Add_Prefix(pos,-1);k=pos;v=1; 83 Add_Bit(num); 84 ans+=Left+Right; 85 } 86 return 0; 87 } 88 ///================fuction code==================== 89 void Add_Bit(int x){ 90 while (x<=n){ 91 Add_Seg(BitTree[x],1,n); 92 x+=lowbit(x); 93 } 94 } 95 void Add_Prefix(int x,int val){ 96 while (x<=n){ 97 Prefix[x]+=val; 98 x+=lowbit(x); 99 } 100 } 101 int Query_Prefix(int x){ 102 int res=0; 103 while (x>0){ 104 res+=Prefix[x]; 105 x-=lowbit(x); 106 } 107 return res; 108 } 109 long long Query_Bit(int x){ 110 long long res=0; 111 while (x>0){ 112 res+=Query_Seg(BitTree[x],1,n,0); 113 x-=lowbit(x); 114 } 115 return res; 116 } 117 void Add_Seg(Seg_Node *&Node,int l,int r){ 118 if (Node==NULL) Node=new(Seg_Node); 119 int m=(l+r)>>1; 120 if (l==r){ 121 Node->addv+=v; 122 Node->sum+=v; 123 return ; 124 } 125 if (m>=k) Add_Seg(Node->lc,l,m); 126 else Add_Seg(Node->rc,m+1,r); 127 update(Node,l,r); 128 } 129 void update(Seg_Node *&Node,int l,int r){ 130 Node->sum=0; 131 if (Node->lc!=NULL) Node->sum+=Node->lc->sum; 132 if (Node->rc!=NULL) Node->sum+=Node->rc->sum; 133 Node->sum+=(r-l+1)*Node->addv; 134 } 135 long long Query_Seg(Seg_Node *&Node,int l,int r,int add){ 136 if (Node==NULL) return (r-l+1)*add; 137 if (L<=l&&r<=R) return Node->sum+add*(r-l+1); 138 int m=(l+r)>>1; 139 long long Left=0,Right=0; 140 if (m>=L) Left=Query_Seg(Node->lc,l,m,add+Node->addv); 141 if (m<R) Right=Query_Seg(Node->rc,m+1,r,add+Node->addv); 142 return Left+Right; 143 } 144 inline void qread(int &x){ 145 char cha; 146 while(cha=getchar()) if(isdigit(cha)) break; 147 x=cha-'0'; 148 while(cha=getchar()){ 149 if(!isdigit(cha)) break; 150 x=10*x+cha-'0'; 151 } 152 } 153 void Add_Bit(int *P,int x){ 154 while (x<=n){ 155 P[x]++; 156 x+=lowbit(x); 157 } 158 } 159 int Query_Bit(int *P,int x){ 160 int res=0; 161 while (x>0){ 162 res+=P[x]; 163 x-=lowbit(x); 164 } 165 return res; 166 }