這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
數組的定位o(1),插入o(n). 鏈表的定位o(n),插入o(1).
所以把二者結合,是複雜度均攤為 sqrt(n)
設每塊的大小為S,那麼刪除或者添加元素時,維護逆序對數的複雜度是O(S+\frac{P}{S}* \log n)o(S+(p/s)*logn),S是塊內直接暴力更新逆序對的代價,(n/s)∗logn在前面塊找比它大和在後面塊中找比它小的代價,P表示當前元素的個數。為了使這兩部分複雜度盡量均攤讓S=\frac{P}{S}* \log nS=(p/s)*logn,S取sqrt(p*logn)。直接通過分塊暴力添加和刪除時,塊的大小會退化,。。。。。(註:原官方題解說重構,不太清楚怎麼叫重構。這裡為了防止退化,在每個塊元素過多時採取分裂操作)。因此整個問題的複雜度為O(m\sqrt{n\log n})O(m*sqrt(n*logn)).
/************************************************************************* > File Name: a.cpp > Author: TechMonster > Mail: 928221136@qq.com > Created Time: 二 7/ 5 09:14:50 2016 ************************************************************************/#include<iostream>#include<stdio.h>#include<string.h>#include<ctype.h>#include<string>#include<math.h>#include<map>#include<set>#include<vector>#include<queue>#include<algorithm>using namespace std;template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }#define ls (o<<1) #define rs (o<<1|1) #define MS(x,y) memset(x,y,sizeof(x))#define MC(x, y) memcpy(x, y, sizeof(x))#define MP(x,y) make_pair(x,y)#define PB(x) push_back(x)#define FF first#define SS secondtypedef long long LL;const int INF = 0x3f3f3f3f;const int N = 50010;const int lim = 150;void add(int *c,int x,int v){while(x <= 20000){c[x] += v;x += x&-x;}}int sum(int *c,int x){int ret = 0;while(x>0){ret += c[x];x -= x&-x;}return ret;}struct data{int s,a[305],c[20010];data *nxt;data(){MS(c,0);nxt = NULL;}};int n,m;data *root;void insert(int x,int pos){data *now = root;if(root == NULL){root = new data;root->s = 1;root->a[1] = x;add(root->c,x,1);return;}while(pos > now->s && now->nxt != NULL){pos -= now->s;now = now->nxt;}memmove(now->a+pos+1,now->a+pos,sizeof(int)*(now->s-pos+1));now->a[pos] = x;add(now->c,x,1);now->s++;if(now->s == 2*lim)//分裂{data *lst = new data;lst->nxt = now->nxt;now->nxt = lst;memcpy(lst->a+1,now->a+lim+1,sizeof(int)*lim);lst->s = now->s = lim;for(int i = 1; i <= lim; ++i){add(now->c,lst->a[i],-1);add(lst->c,lst->a[i],1);}}}int find(int pos){data *now = root;while(pos > now->s && now->nxt != NULL){pos -= now->s;now = now->nxt;}return now->a[pos];}int calc(int pos){data *now = root;int ret = 0;int x = find(pos);while(pos > now->s && now->nxt != NULL){ret += sum(now->c,20000) - sum(now->c,x);pos -= now->s;now = now->nxt;}for(int i = 1; i < pos; ++i)if(now->a[i] > x) ret++;for(int i = pos+1; i <= now->s; ++i)if(now->a[i] < x) ret++;while(now->nxt != NULL){now = now->nxt;ret += sum(now->c,x-1);}return ret;}void del(int pos){data *now = root;while(pos > now->s && now->nxt != NULL){pos -= now->s;now = now->nxt;}add(now->c,now->a[pos],-1);memmove(now->a+pos,now->a+pos+1,sizeof(int)*(now->s-pos));now->s--;}void destroy(data *now){if(now->nxt != NULL) destroy(now->nxt);delete now;}void solve(){root = NULL;//delete 後 ,root會指向非法記憶體,剛開始忘了初始化一直reint ope,u,v,ans = 0;int x,y;for(int i = 1; i <= n; ++i){scanf("%d",&u);insert(u,i);ans += calc(i);}for(int i = 1; i <= m; ++i){scanf("%d",&ope);if(ope == 1){scanf("%d",&x);ans -= calc(x);del(x);}else{scanf("%d%d",&x,&y);insert(y,x+1);ans += calc(x+1);}printf("%d\n",ans);}destroy(root);}int main(){while(~scanf("%d%d",&n,&m))solve();return 0;}