本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
题目链接:BZOJ2141
正解:线段树套$Treap$
解题报告:
树套树写起来还是挺爽的==
这就是一个维护动态逆序对的问题,考虑树套树,线段树用来资瓷区间查询,线段树上每个节点维护一个$Treap$,用来资瓷区间小于某个数的个数的查询。
那么思想就很直观了,初始的时候直接把每个点插入线段树,经过的节点上的$Treap$都插入一遍,这样做的空间复杂度是$O(nlogn)$的,因为每个点都被$build$了$logn$次。
查询的话,直接在$Treap$上查询就好了,记得每次交换的时候还需要修改$Treap$上的权值。
话说这道题跟我上次在codeforces上做的某题几乎长得一模一样啊,so这道题也可以分块啦...
//It is made by ljh2000 //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。 #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <ctime> #define lc root<<1 #define rc root<<1|1 using namespace std; typedef long long LL; const int MAXN = 50011; const int MAXM = 1000011; int n,m,val[MAXN],tot,size[MAXM],a[MAXM],r[MAXM],tr[MAXM][2],ql,qr,ans; inline int getint(){int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;} struct node{ int rt,maxl,minl; inline void Init(){ maxl=-2147483647; minl=2147483647; } inline void update(int x){ size[x]=size[tr[x][0]]+size[tr[x][1]]+1; } inline void R(int &p,bool k){ int tt=tr[p][k]; tr[p][k]=tr[tt][k^1]; tr[tt][k^1]=p; update(p); update(tt); p=tt; } inline void insert(int &p,int x){ if(!p) { p=++tot; a[p]=x; size[p]=1; r[p]=rand(); maxl=max(maxl,x); minl=min(minl,x); return ; } size[p]++; bool k=(x>a[p]); insert(tr[p][k],x); if(r[ tr[p][k] ]>r[p]) R(p,k); } inline int querymin(int p,int x){ int tot=0; if(minl>=x) return 0; while(p) { if(a[p]<x) tot+=size[tr[p][0]]+1,p=tr[p][1]; else p=tr[p][0]; } return tot; } inline int querymax(int p,int x){ int tot=0; if(maxl<=x) return 0; while(p) { if(a[p]>x) tot+=size[tr[p][1]]+1,p=tr[p][0]; else p=tr[p][1]; } return tot; } inline int rank(int p,int x){ int tot=0; while(p) { if(a[p]<=x) tot+=size[tr[p][0]]+1,p=tr[p][1];//!!! else p=tr[p][0]; } return tot;//!!! } inline void out(int &p){ if(!tr[p][0] || !tr[p][1]) { p=tr[p][0]+tr[p][1]; return ; } bool k=(r[tr[p][1]]>r[tr[p][0]]) ; R(p,k); size[p]--;//!!! out(tr[p][k^1]); } inline void del(int &p,int x){ size[p]--;//!!! if(size[tr[p][0]]+1==x) { out(p); return ; } if(size[tr[p][0]]>=x) del(tr[p][0],x); else del(tr[p][1],x-size[tr[p][0]]-1); } inline void modify(int x,int nw){ int rk=rank(rt,x); del(rt,rk); insert(rt,nw); } }t[MAXN*3]; inline void build(int root,int l,int r,int pos,int x){ t[root].insert(t[root].rt,x); if(l==r) return ; int mid=(l+r)>>1; if(pos<=mid) build(lc,l,mid,pos,x); else build(rc,mid+1,r,pos,x); } inline void querymin(int root,int l,int r,int type,int x){ if(ql<=l && r<=qr) { ans += type * t[root].querymin(t[root].rt,x); return ; } int mid=(l+r)>>1; if(ql<=mid) querymin(lc,l,mid,type,x); if(qr>mid) querymin(rc,mid+1,r,type,x); } inline void querymax(int root,int l,int r,int type,int x){ if(ql<=l && r<=qr) { ans += type * t[root].querymax(t[root].rt,x); return ; } int mid=(l+r)>>1; if(ql<=mid) querymax(lc,l,mid,type,x); if(qr>mid) querymax(rc,mid+1,r,type,x); } inline void modify(int root,int l,int r,int pos,int x){ t[root].modify(val[pos],x); if(l==r) return ; int mid=(l+r)>>1; if(pos<=mid) modify(lc,l,mid,pos,x); else modify(rc,mid+1,r,pos,x); } inline void work(){ srand(121312); n=getint(); for(int i=1;i<=n*3;i++) t[i].Init(); for(int i=1;i<=n;i++) val[i]=getint(),build(1,1,n,i,val[i]); for(int i=1;i<=n;i++) ql=i,qr=n,querymin(1,1,n,1,val[i]); printf("%d ",ans); m=getint(); int l,r; while(m--) { l=getint(); r=getint(); if(l>r) swap(l,r); if(l==r || val[l]==val[r]) { printf("%d ",ans); continue; } if(r-l>1) { ql=l+1; qr=r-1; querymin(1,1,n,-1,val[l]); querymax(1,1,n,1,val[l]); querymax(1,1,n,-1,val[r]); querymin(1,1,n,1,val[r]); } if(val[l]>val[r]) ans--; else if(val[l]<val[r]) ans++; //记得在线段树的Treap中修改对应权值 modify(1,1,n,l,val[r]); modify(1,1,n,r,val[l]); swap(val[l],val[r]); printf("%d ",ans); } //cout<<endl; //cout<<clock()<<endl; } int main() { #ifndef ONLINE_JUDGE freopen("2141.in","r",stdin); freopen("2141.out","w",stdout); #endif work(); return 0; } //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。