数组的定位o(1),插入o(n). 链表的定位o(n),插入o(1).
所以把二者结合,是复杂度均摊为 sqrt(n)
设每块的大小为S,那么删除或者添加元素时,维护逆序对数的复杂度是o(S+(p/s)*logn),S是块内直接暴力更新逆序对的代价,(n/s)∗logn在前面块找比它大和在后面块中找比它小的代价,P表示当前元素的个数。为了使这两部分复杂度尽量均摊让S=(p/s)*logn,S取sqrt(p*logn)。直接通过分块暴力添加和删除时,块的大小会退化,。。。。。(注:原官方题解说重构,不太清楚怎么叫重构。这里为了防止退化,在每个块元素过多时采取分裂操作)。因此整个问题的复杂度为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 second typedef 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会指向非法内存,刚开始忘了初始化一直re int 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; }
有疑问加站长微信联系(非本文作者)