/*hdu 5193 分块 树状数组 逆序对 题意: 给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除。求每次修改后逆序对的个数。 限制: 1 <= n,m <= 20000; 1 <= ai <= n 思路: 插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个。 外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力。查找权值个数时,使用树状数组比较方便。内层通过树状数组维护权值。 每次更新即为,在前面块找比它大和在后面块中找比它小的代价。 O(m*(sqrt(n)+sqrt(n)*log(n))) */ #include<iostream> #include<cstdio> #include<vector> #include<cstring> #include<cmath> using namespace std; #define LL __int64 #define PB push_back const int N=355; const int M=20005; int tot; vector<int> vec[N]; int pre[N],nxt[N]; int SZ; int BIT[N][M]; int lowbit(int x){ return x&-x; } int sum(int i,int x){ int s=0; while(x>0){ s+=BIT[i][x]; x-=lowbit(x); } return s; } void update(int i,int x,int w){ while(x<M){ BIT[i][x]+=w; x+=lowbit(x); } } vector<int> A; void init(){ tot=0; memset(pre,-1,sizeof(pre)); memset(nxt,-1,sizeof(nxt)); memset(BIT,0,sizeof(BIT)); for(int i=0;i<N;++i) vec[i].clear(); A.clear(); } LL merge_count(vector<int> &a){ int n=a.size(); if(n<=1) return 0; LL cnt=0; vector<int> b(a.begin(),a.begin()+n/2); vector<int> c(a.begin()+n/2,a.end()); cnt+=merge_count(b); cnt+=merge_count(c); int ai=0,bi=0,ci=0; while(ai<n){ if(bi<b.size() && (ci==c.size() || b[bi]<=c[ci])) a[ai++]=b[bi++]; else{ cnt+=(LL)(n/2-bi); a[ai++]=c[ci++]; } } return cnt; } int count_left(int now,int h){ int p=0; int ret=0; while(p!=now){ ret+=vec[p].size()-sum(p,h); p=nxt[p]; } return ret; } int count_right(int now,int h){ int p=nxt[now]; int ret=0; while(p!=-1){ ret+=sum(p,h-1); p=nxt[p]; } return ret; } void print(){ cout<<"---"<<endl; int p=0; while(p!=-1){ for(int j=0;j<vec[p].size();++j){ cout<<vec[p][j]<<' '; } cout<<endl; p=nxt[p]; } cout<<"---"<<endl; } int count_in(int now,int id,int h){ int ret=0; for(int i=0;i<id;++i){ // if(vec[now][i]>h) ++ret; } for(int i=id;i<vec[now].size();++i){ // if(vec[now][i]<h) ++ret; } return ret; } int ins(int id,int h){ int p=0; while(id>vec[p].size()){ id-=vec[p].size(); p=nxt[p]; } vec[p].insert(vec[p].begin()+id,h); update(p,h,1); int left=count_left(p,h); int right=count_right(p,h); int in=count_in(p,id,h); if(vec[p].size()>SZ){ int dy=vec[p][vec[p].size()-1]; vec[p].pop_back(); update(p,dy,-1); if(nxt[p]==-1 || vec[nxt[p]].size()==SZ){ int q=nxt[p]; nxt[p]=++tot; pre[tot]=p; nxt[tot]=q; pre[q]=tot; vec[tot].push_back(dy); update(tot,dy,1); } else{ int q=nxt[p]; vec[q].insert(vec[q].begin(),dy); update(q,dy,1); } } return left+in+right; } int qui(int id){ int p=0; while(id>vec[p].size()){ id-=vec[p].size(); p=nxt[p]; } int h=vec[p][id-1]; int left=count_left(p,h); int right=count_right(p,h); int in=count_in(p,id,h); vec[p].erase(vec[p].begin()+id-1); // update(p,h,-1); return left+right+in; } int main(){ int n,m; int a; while(scanf("%d%d",&n,&m)!=EOF){ init(); SZ=sqrt(n+m); for(int i=0;i<n;++i){ scanf("%d",&a); A.PB(a); vec[tot].PB(a); update(tot,a,1); if(vec[tot].size()==SZ){ nxt[tot]=tot+1; ++tot; pre[tot]=tot-1; } } LL ans=merge_count(A); int cm,x,y; for(int i=0;i<m;++i){ scanf("%d",&cm); if(cm==0){ scanf("%d%d",&x,&y); ans+=(LL)ins(x,y); printf("%I64d\n",ans); } else{ scanf("%d",&x); ans-=(LL)qui(x); printf("%I64d\n",ans); } //print(); } } return 0; }
原文:http://blog.csdn.net/whai362/article/details/44777727