本文版权归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\n",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\n",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\n",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;
}
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。