【CQOI2011】动态逆序对 BZOJ3295

Description

对于序列A,它的逆序对数定义为满足 i< j,且A i>A j的数对( i, j)的个数。给1到 n的一个排列,按照某种顺序依次删除 m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

Input

输入第一行包含两个整数 nm,即初始元素的个数和删除的元素个数。以下 n行每行包含一个1到 n之间的正整数,即初始排列。以下 m行每行一个正整数,依次为每次删除的元素。
 

Output

 
输出包含 m行,依次为删除每个元素之前,逆序对的个数。

Sample Input

5 4
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)。

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\n",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 }
BZOJ3295

 

你可能感兴趣的:(ZOJ)