• [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)


    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树)

    题面

    给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数

    分析

    每次都对整个序列求逆序对显然不行,考虑每次删除对逆序对个数的影响

    假如删除的数为x,x在序列中的位置为pos[x],那么包含x的逆序对个数为位置在[1,pos[x]-1]中大于x的数+位置在[pos[x]+1,n]中小于x的数,每次删除只要减去这些就可以了

    那么这个问题其实就转化成查询位置在[L,R]内,且值域在[l,r]内的数的个数。本质上和带修区间第k大BZOJ 1901 Dynamic Rankings是一样的,外层用树状数组维护位置,内层不用可持久化,直接用权值线段树即可

    那么我们像树状数组那样维护n棵权值线段树,不同的是每棵权值线段树里保存的是,a[i-lowbit(i)+1]~a[i]有多少个值落在区间[l,r]内

    对于查询[ql,qr]中有多少个值时的做差
    我们要像树状数组求和那样,把root[i],root[i-lowbit(i)],....共O(logn)棵权值线段树的值加起来,才能得到a[1]~a[i]有多少个数落在1~qr里面,1~(ql-1)同理,维护两个临时数组x,y存储这O(logn)棵权值线段树的根即可

    对于单点修改,我们像树状数组修改那样,往O(logn)棵权值线段树中插入即可

    时间复杂度(O(m log ^2 n)),常数略大

    注意答案一定要开long long!!!!

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 100000
    #define maxm 100000
    #define maxnlogn 50000000
    #define maxlogn 20 
    using namespace std;
    inline void qread(int &x) {
    	x=0;
    	int sign=1;
    	char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') sign=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	x=x*sign;
    }
    inline void qprint(long long x) {
    	if(x<0) {
    		putchar('-');
    		qprint(-x);
    	} else if(x==0) {
    		putchar('0');
    		return;
    	} else {
    		if(x>=10) qprint(x/10);
    		putchar('0'+x%10);
    	}
    }
    
    int n,m;
    int a[maxn+5];
    struct segment_tree_val{
    #define lson(x) (tree[x].ls)
    #define rson(x) (tree[x].rs)
    	struct node{
    		int ls;
    		int rs;
    		int v;
    	}tree[maxnlogn+5];
    	int ptr;
    	void push_up(int x){
    		tree[x].v=tree[lson(x)].v+tree[rson(x)].v;
    	}
    	void update(int &x,int upos,int uval,int l,int r){
    		if(!x) x=++ptr;
    		if(l==r){
    			tree[x].v+=uval;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(upos<=mid) update(tree[x].ls,upos,uval,l,mid);
    		else update(tree[x].rs,upos,uval,mid+1,r);
    		push_up(x);
    	}
    	int totx,toty;
    	int x[maxn+5],y[maxn+5];
    	int query_less(int k,int l,int r){//查询<k的数的个数 
    		int cnt=0;
    		while(l!=r){
    			int mid=(l+r)>>1;
    			if(k<=mid){
    				for(int i=1;i<=totx;i++) x[i]=lson(x[i]);
    				for(int i=1;i<=toty;i++) y[i]=lson(y[i]);
    				r=mid;
    			}else{
    				for(int i=1;i<=totx;i++) cnt-=tree[lson(x[i])].v;
    				for(int i=1;i<=toty;i++) cnt+=tree[lson(y[i])].v;
    				for(int i=1;i<=totx;i++) x[i]=rson(x[i]);
    				for(int i=1;i<=toty;i++) y[i]=rson(y[i]);
    				l=mid+1;
    			}
    		}
    		return cnt;
    	}
    	int query_more(int k,int l,int r){//查询>k的数的个数 
    		int cnt=0;
    		while(l!=r){
    			int mid=(l+r)>>1;
    			if(k<=mid){
    				for(int i=1;i<=totx;i++) cnt-=tree[rson(x[i])].v;
    				for(int i=1;i<=toty;i++) cnt+=tree[rson(y[i])].v;
    				for(int i=1;i<=totx;i++) x[i]=lson(x[i]);
    				for(int i=1;i<=toty;i++) y[i]=lson(y[i]);
    				r=mid;
    			}else{
    				for(int i=1;i<=totx;i++) x[i]=rson(x[i]);
    				for(int i=1;i<=toty;i++) y[i]=rson(y[i]);
    				l=mid+1;
    			}
    		}
    		return cnt;
    	}
    }T1;
    
    struct fenwick_tree{
    	inline int lowbit(int x){
    		return x&(-x);
    	} 
    	int root[maxn+5];
    	void update(int t2pos,int t1pos,int val){
    		for(int i=t2pos;i<=n;i+=lowbit(i)){
    			T1.update(root[i],t1pos,val,1,n);
    		}
    	}
    	int query_less(int lpos,int rpos,int val){
    		T1.totx=T1.toty=0;
    		for(int i=lpos-1;i;i-=lowbit(i)) T1.x[++T1.totx]=root[i];
    		for(int i=rpos;i;i-=lowbit(i)) T1.y[++T1.toty]=root[i]; 
    		return T1.query_less(val,1,n);
    	}
    	int query_more(int lpos,int rpos,int val){
    		T1.totx=T1.toty=0;
    		for(int i=lpos-1;i;i-=lowbit(i)) T1.x[++T1.totx]=root[i];
    		for(int i=rpos;i;i-=lowbit(i)) T1.y[++T1.toty]=root[i]; 
    		return T1.query_more(val,1,n);
    	}
    }T2;
    
    int pos[maxn+5];
    long long ans=0;
    int main(){
    //	freopen("4.in","r",stdin);
    //	freopen("4.out","w",stdout); 
    //	freopen("1.txt","r",stdin);
    	int x;
    	qread(n);
    	qread(m);
    	for(int i=1;i<=n;i++){
    		qread(a[i]);
    		pos[a[i]]=i;
    		ans+=T2.query_more(1,i-1,a[i]);
    		T2.update(i,a[i],1); 
    	}
    	qprint(ans);
    	putchar('
    ');
    	for(int i=1;i<m;i++){
    		qread(x);
    		ans-=T2.query_more(1,pos[x]-1,x);
    		ans-=T2.query_less(pos[x]+1,n,x);
    		qprint(ans);
    		putchar('
    ');
    		T2.update(pos[x],x,-1); 
    	}
    }
    /*
    5 4
    1 5 3 4 2
    5 
    1
    4
    2
    
    */ 
    
    
  • 相关阅读:
    超详细的sql2005图解安装全过程【图文】SQL Server 2005 安装图解(图文详解+全程截图)
    C# WinForm控件的拖动和缩放的实现
    C#中使用组合键事件,c#2005中组合键的应用
    C#判断Shift,Alt,Ctrl是否被按下,确定所按下的组合键
    详解破解VS2010正式版的方法(仅供技术交流)
    C# listview中显示imagelist中的图片
    序列化
    收集一些常用的正则表达式【转载】
    iframe+ajaxSubmit结合续篇(判断图片(文件)大小,上传图片,验证码刷新)
    完美去掉a标签和按钮加背景图片阴影
  • 原文地址:https://www.cnblogs.com/birchtree/p/11287900.html
Copyright © 2020-2023  润新知