zoukankan      html  css  js  c++  java
  • 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
    ",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;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    取球问题
    汉字首字母
    上三角
    循环小数
    拓扑排序
    倒水
    equals方法使用技巧
    Java库中的集合
    win10安装Redis方法以及基本配置
    c、c++函数随机
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6637005.html
Copyright © 2011-2022 走看看