uva 11990 - ``Dynamic'' Inversion
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3141
题意:给一个N的排列。有M个操作,每次把排列中的一个数删除,问把这个数删除前总的逆序数是多少。
思路:线段树+树状数组(也就是是树套树)。
建树时,要把各区间内的数排好序。
线段树中每个节点维护一个树状数组,记录这个区间有多少个数已删除。
查找时,二分这个数在这个区间上的位置,然后算出小于它的有多少个,大于他的有多少个,再用树状数组去除删除的。
更新时,二分这个数在这个区间的位置,更新相应的树状数组。
想法应该很容易想到,但主要处理区间的树状数组有点技巧,把一个一维数组弄成多个树状数组,看代码吧。
总的时间复杂度大概是N*log(N)+M*log(N)*log(N).

#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #define LB(x) (x)&(-x) using namespace std; const int maxn = 200005; int as[23][maxn]; int bs[23][maxn]; int tmp[maxn],cs[maxn]; int n,m; long long tot; void add(int a[],int x,int v,int n){ for(;x<=n;x+=LB(x))a[x]+=v; } int getsum(int a[],int x,int n = 0){ int v = 0; for(;x>n;x-=LB(x))v+=a[x]; return v; } void build(int rt,int l,int r,int d) { int md = (l + r) >> 1; for(int i = l; i <= r; ++ i) as[d][i]=as[d-1][i],bs[d][i]=0; if(l==r)return; build(rt<<1,l,md,d+1); build(rt<<1|1,md+1,r,d+1); sort(as[d]+l,as[d]+r+1);//排序 } //二分区间[a,b],得到v所在的位置 int bitser(int a,int b,int d,int v) { int l = a,r = b,md; while(l < r){ md = (l + r) >> 1; if(as[d][md]>=v)r = md; else l = md + 1; } if(as[d][l]>v)--l; return l; } void query(int rt,int l,int r,int L,int R,int v,int d,int f) { int md = (l + r) >> 1; if(L<=l && r<=R){ int k = bitser(l,r,d,v); int t = getsum(bs[d],k,l-1);//求[l,r]区间上k位置前有多少个数删除了 if(!f){ k = r - k; t = getsum(bs[d],r,l-1) - t; }else k -= l - 1; tot -= k - t; return ; } if(l>=r)return; if(L<=md)query(rt<<1,l,md,L,R,v,d+1,f); if(R>md )query(rt<<1|1,md+1,r,L,R,v,d+1,f); } void update(int rt,int l,int r,int L,int v,int d) { int md = (l + r) >> 1; if(l==r){ add(bs[d],l,1,r); return ; } if(l>=r)return; if(L<=md)update(rt<<1,l,md,L,v,d+1); else update(rt<<1|1,md+1,r,L,v,d+1); int k = bitser(l,r,d,v); add(bs[d],k,1,r); } int main() { while(scanf("%d%d",&n,&m)==2){ tot = 0; for(int i = 0; i <= n + 1; ++ i)tmp[i]=0; for(int i = 1; i <= n; ++ i){ scanf("%d",&as[0][i]);cs[as[0][i]]=i; tot += i - 1 - getsum(tmp,as[0][i]); add(tmp,as[0][i],1,n); } build(1,1,n,1); int k; while(m--){ scanf("%d",&k); printf("%lld\n",tot); if(tot){ query(1,1,n,1,cs[k]-1,k,1,0); query(1,1,n,cs[k]+1,n,k,1,1); update(1,1,n,cs[k],k,1); } } } return 0; }