码迷,mamicode.com
首页 > 编程语言 > 详细

hdu 5193 分块 树状数组 逆序对

时间:2015-03-31 14:50:01      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:algorithm

hdu 5193 分块 树状数组 逆序对
题意:
给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除。求每次修改后逆序对的个数。

限制:
1 <= n,m <= 20000; 1 <= ai <= n

思路:
插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个。
外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力。查找权值个数时,使用树状数组比较方便。内层通过树状数组维护权值。
每次更新即为,在前面块找比它大和在后面块中找比它小的代价。
O(m*(sqrt(n)+sqrt(n)*log(n)))

/*hdu 5193 分块 树状数组 逆序对
  题意:
  给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除。求每次修改后逆序对的个数。
  限制:
  1 <= n,m <= 20000; 1 <= ai <= n
  思路:
  插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个。
  外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力。查找权值个数时,使用树状数组比较方便。内层通过树状数组维护权值。
  每次更新即为,在前面块找比它大和在后面块中找比它小的代价。
  O(m*(sqrt(n)+sqrt(n)*log(n)))
 */
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
#define LL __int64
#define PB push_back
const int N=355;
const int M=20005;
int tot;
vector<int> vec[N];
int pre[N],nxt[N];
int SZ;
int BIT[N][M];
int lowbit(int x){ return x&-x; }
int sum(int i,int x){
	int s=0;
	while(x>0){
		s+=BIT[i][x];
		x-=lowbit(x);
	}
	return s;
}
void update(int i,int x,int w){
	while(x<M){
		BIT[i][x]+=w;
		x+=lowbit(x);
	}
}
vector<int> A;
void init(){
	tot=0;
	memset(pre,-1,sizeof(pre));
	memset(nxt,-1,sizeof(nxt));
	memset(BIT,0,sizeof(BIT));
	for(int i=0;i<N;++i)
		vec[i].clear();
	A.clear();
}
LL merge_count(vector<int> &a){
	int n=a.size();
	if(n<=1) return 0;
	LL cnt=0;
	vector<int> b(a.begin(),a.begin()+n/2);
	vector<int> c(a.begin()+n/2,a.end());
	cnt+=merge_count(b);
	cnt+=merge_count(c);
	int ai=0,bi=0,ci=0;
	while(ai<n){
		if(bi<b.size() && (ci==c.size() || b[bi]<=c[ci]))
			a[ai++]=b[bi++];
		else{
			cnt+=(LL)(n/2-bi);
			a[ai++]=c[ci++];
		}
	}
	return cnt;
}
int count_left(int now,int h){
	int p=0;
	int ret=0;
	while(p!=now){
		ret+=vec[p].size()-sum(p,h);
		p=nxt[p];
	}
	return ret;
}
int count_right(int now,int h){
	int p=nxt[now];
	int ret=0;
	while(p!=-1){
		ret+=sum(p,h-1);
		p=nxt[p];
	}
	return ret;
}
void print(){
	cout<<"---"<<endl;
	int p=0;
	while(p!=-1){
			for(int j=0;j<vec[p].size();++j){
				cout<<vec[p][j]<<' ';
			}
			cout<<endl;
			p=nxt[p];
	}
	cout<<"---"<<endl;
}
int count_in(int now,int id,int h){
	int ret=0;
	for(int i=0;i<id;++i){	//
		if(vec[now][i]>h) ++ret;
	}
	for(int i=id;i<vec[now].size();++i){	//
		if(vec[now][i]<h) ++ret;
	}
	return ret;
}
int ins(int id,int h){
	int p=0;
	while(id>vec[p].size()){
		id-=vec[p].size();
		p=nxt[p];
	}
	vec[p].insert(vec[p].begin()+id,h);
	update(p,h,1);
	int left=count_left(p,h);
	int right=count_right(p,h);
	int in=count_in(p,id,h);
	if(vec[p].size()>SZ){
		int dy=vec[p][vec[p].size()-1];
		vec[p].pop_back();
		update(p,dy,-1);
		if(nxt[p]==-1 || vec[nxt[p]].size()==SZ){
			int q=nxt[p];
			nxt[p]=++tot;
			pre[tot]=p;
			nxt[tot]=q;
			pre[q]=tot;

			vec[tot].push_back(dy);
			update(tot,dy,1);
		}
		else{
			int q=nxt[p];
			vec[q].insert(vec[q].begin(),dy);
			update(q,dy,1);
		}
	}
	return left+in+right;
}
int qui(int id){
	int p=0;
	while(id>vec[p].size()){
		id-=vec[p].size();
		p=nxt[p];
	}
	int h=vec[p][id-1];
	int left=count_left(p,h);
	int right=count_right(p,h);
	int in=count_in(p,id,h);
	vec[p].erase(vec[p].begin()+id-1);	//
	update(p,h,-1);
	return left+right+in;
}
int main(){
	int n,m;
	int a;
	while(scanf("%d%d",&n,&m)!=EOF){
		init();
		SZ=sqrt(n+m);
		for(int i=0;i<n;++i){
			scanf("%d",&a);
			A.PB(a);
			vec[tot].PB(a);
			update(tot,a,1);
			if(vec[tot].size()==SZ){
				nxt[tot]=tot+1;
				++tot;
				pre[tot]=tot-1;
			}
		}


		LL ans=merge_count(A);
		int cm,x,y;
		for(int i=0;i<m;++i){
			scanf("%d",&cm);
			if(cm==0){
				scanf("%d%d",&x,&y);
				ans+=(LL)ins(x,y);
				printf("%I64d\n",ans);
			}
			else{
				scanf("%d",&x);
				ans-=(LL)qui(x);
				printf("%I64d\n",ans);
			}
			//print();
		}
	}
	return 0;
}


hdu 5193 分块 树状数组 逆序对

标签:algorithm

原文地址:http://blog.csdn.net/whai362/article/details/44777727

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!