BZOJ3295:[CQOI2011]动态逆序对

浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3295

树状数组套线段树,如题目所言,动态维护答案即可。

写了树套树之后我才发现递归是个多么傻逼的玩意儿……

时间复杂度:\(O(nlog^2n)\)

空间复杂度:\(O(nlogn)\)

代码如下:

#include <cstdio>
using namespace std;
typedef long long ll;
#define low(i) ((i)&(-(i)))

const int maxn=1e5+5;

ll ans;
int n,m;
int pos[maxn];

inline int read() {
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	return x*f;
}

struct segment_tree {
	int tot;
	int ls[maxn*85],rs[maxn*85],sum[maxn*85];

	inline int query(int p,int l,int r,int pos,int opt) {
		int res=0;
		while(l!=r) {
			int mid=(l+r)>>1;
			if(pos<=mid) {
				if(opt)res+=sum[rs[p]];
				p=ls[p],r=mid;
			}
			else {
				if(!opt)res+=sum[ls[p]];
				p=rs[p],l=mid+1;
			}
		}
		return res;
	}

	inline void change(int p,int l,int r,int pos,int v) {
		if(!p)p=++tot;
		while(1) {
			sum[p]+=v;if(l==r)break;
			int mid=(l+r)>>1;
			if(pos<=mid) {
				if(!ls[p])ls[p]=++tot;
				p=ls[p],r=mid;
			}
			else {
				if(!rs[p])rs[p]=++tot;
				p=rs[p],l=mid+1;
			}
		}
	}
}T;

struct TreeArray {
	int rt[maxn];

	inline int query(int pos,int v,int opt) {
		int res=0;
		for(int i=pos;i;i-=low(i))
			res+=T.query(rt[i],1,n,v,opt);
		return res;
	}

	inline void change(int pos,int x,int v) {
		for(int i=pos;i<=n;i+=low(i)) {
			if(!rt[i])rt[i]=++T.tot;
			T.change(rt[i],1,n,x,v);
		}
	}
}bit;

int main() {
	n=read(),m=read();
	for(int i=1;i<=n;i++) {
		int x=read();pos[x]=i;
		ans+=bit.query(i-1,x,1);
		bit.change(i,x,1);
	}
	for(int i=1;i<=m;i++) {
		printf("%lld\n",ans);
		int x=read();
		ans-=bit.query(pos[x]-1,x,1);
		ans-=bit.query(n,x,0)-bit.query(pos[x],x,0);
		bit.change(pos[x],x,-1);
	}
	return 0;
}
posted @ 2018-12-24 20:00  AKMer  阅读(128)  评论(0编辑  收藏  举报