BZOJ2141 排队

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

  

posted @ 2017-03-28 21:40  ljh_2000  阅读(198)  评论(0编辑  收藏  举报