题意:
给出一段长为n的数列,求其逆序对数;
然后给出m个操作,每次操作给出l,r;
交换l,r并输出操作之后的逆序对数;
n<=2x10^4,m<=2x10^3;
题解:
求逆序对本来是一个很简单的事情,然而动态修改就不能用树状数组直接搞了;
因为树状数组求逆序对是不支持区分某个数在它前面还是后面的;
所以考虑求在它之前小于它的数的个数,用线段树维护区间,套treap维护排名;
在求排名的过程中顺便记录一个cnt表示区间中与这个数相等的点;
然后对于每次修改,逆序对数ans的更改:
a[ l ]移到后面就是ans减去比它小的个数,加上比它大的个数;
比它大的就是区间长减去cnt减去比它小的咯;
a[ r ]同理,之后再维护树套树就可以了;
HINT:
l可能大于r;
小心重复计算区间端点的逆序对;
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 20001 #define M 2000000 #define lson l,mid,no<<1 #define rson mid+1,r,no<<1|1 using namespace std; struct node { int val,rnd,l,r,w,size; }treap[M]; int n,m,tot,ans,cnt; int root[N<<2],a[N]; void Pushup(int no) { treap[no].size=treap[treap[no].l].size+treap[treap[no].r].size+treap[no].w; } void lturn(int &no) { int temp=treap[no].r; treap[no].r=treap[temp].l; treap[temp].l=no; treap[temp].size=treap[no].size; Pushup(no); no=temp; } void rturn(int &no) { int temp=treap[no].l; treap[no].l=treap[temp].r; treap[temp].r=no; treap[temp].size=treap[no].size; Pushup(no); no=temp; } void insert(int &no,int val) { if(!no) { no=++tot; treap[no].size=treap[no].w=1; treap[no].val=val,treap[no].rnd=rand(); return ; } treap[no].size++; if(val==treap[no].val) treap[no].w++; else if(val<treap[no].val) { insert(treap[no].l,val); if(treap[treap[no].l].rnd<treap[no].rnd) rturn(no); } else { insert(treap[no].r,val); if(treap[treap[no].r].rnd<treap[no].rnd) lturn(no); } } void del(int &no,int val) { if(val==treap[no].val) { if(treap[no].w>1) treap[no].w--,treap[no].size--; else if(treap[no].l*treap[no].r==0) no=treap[no].l+treap[no].r; else if(treap[treap[no].l].rnd<treap[treap[no].r].rnd) rturn(no),del(no,val); else lturn(no),del(no,val); return ; } treap[no].size--; if(val<treap[no].val) del(treap[no].l,val); else del(treap[no].r,val); } void build(int l,int r,int no,int k,int val) { insert(root[no],val); if(l==r) return ; int mid=(l+r)>>1; if(k<=mid) build(lson,k,val); else build(rson,k,val); } void update(int l,int r,int no,int k,int val,int pre) { del(root[no],pre); insert(root[no],val); if(l==r) return ; int mid=(l+r)>>1; if(k<=mid) update(lson,k,val,pre); else update(rson,k,val,pre); } int ask_rank(int no,int val) { if(!no) return 0; if(val==treap[no].val) { cnt+=treap[no].w; return treap[treap[no].l].size; } else if(val<treap[no].val) return ask_rank(treap[no].l,val); else return treap[treap[no].l].size+treap[no].w+ask_rank(treap[no].r,val); } int get_rank(int l,int r,int no,int st,int en,int val) { if(st<=l&&r<=en) return ask_rank(root[no],val); int mid=(l+r)>>1; if(en<=mid) return get_rank(lson,st,en,val); else if(st>mid) return get_rank(rson,st,en,val); else return get_rank(lson,st,en,val)+get_rank(rson,st,en,val); } int main() { int i,j,k,l,r; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",a+i); build(1,n,1,i,a[i]); cnt=0; ans+=i-get_rank(1,n,1,1,i,a[i]); ans-=cnt; } printf("%d\n",ans); scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d%d",&l,&r); if(l==r||a[l]==a[r]) { printf("%d\n",ans); continue; } if(l>r) swap(l,r); cnt=0; ans-=get_rank(1,n,1,l,r,a[l])<<1; ans+=r-l+1-cnt; cnt=0; ans+=get_rank(1,n,1,l+1,r,a[r])<<1; ans-=r-l-cnt; update(1,n,1,l,a[r],a[l]); update(1,n,1,r,a[l],a[r]); swap(a[l],a[r]); printf("%d\n",ans); } return 0; }
原文地址:http://blog.csdn.net/ww140142/article/details/46003725