2018.11.07【CQOI2011】【BZOJ3295】【洛谷P3157】动态逆序对(树状数组套动态开点线段树)

27 篇文章 0 订阅
2 篇文章 0 订阅

BZOJ传送门

洛谷传送门


解析:

首先我们可以通过一个线段树求出逆序对个数,然后就是乱搞的时间了。

显然每次删除一个数,需要我们查询前面比他大的数的个数和后面比他小的数的个数,这个就是裸的树套树了。这道题可以用树状数组套线段树动态开点。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

cs int N=100005,M=10000007;
int root[N],lc[M],rc[M],siz[M],tot;
int a[N],pos[N],qa[20],qb[20],ta,tb;
int n,m;
ll ans;
inline void update(int &k,int l,int r,cs int &pos,cs int &val){
	if(!k)k=++tot;siz[k]+=val;
	if(l==r)return ;
	int mid=(l+r)>>1;
	if(pos<=mid)update(lc[k],l,mid,pos,val);
	else update(rc[k],mid+1,r,pos,val);
}
#define lowbit(x) ((x)&-(x))
inline int query(int l,int r,int val,bool f){
	ta=tb=0;
	int res=0;
	for(--l;l;l-=lowbit(l))if(root[l])qa[++ta]=root[l];
	for(;r;r-=lowbit(r))if(root[r])qb[++tb]=root[r];
	l=1;r=n;
	while(l<r){
		int mid=(l+r)>>1;
		if(val<=mid){
			if(!f){
				for(int re i=1;i<=ta;++i)res-=siz[rc[qa[i]]];
				for(int re i=1;i<=tb;++i)res+=siz[rc[qb[i]]];
			}
			for(int re i=1;i<=ta;++i)qa[i]=lc[qa[i]];
			for(int re i=1;i<=tb;++i)qb[i]=lc[qb[i]];
			r=mid;
		}
		else{
			if(f){
				for(int re i=1;i<=ta;++i)res-=siz[lc[qa[i]]];
				for(int re i=1;i<=tb;++i)res+=siz[lc[qb[i]]];
			}
			for(int re i=1;i<=ta;++i)qa[i]=rc[qa[i]];
			for(int re i=1;i<=tb;++i)qb[i]=rc[qb[i]];
			l=mid+1;
		}
	}
	return res;
}

signed main(){
	n=getint();
	m=getint();
	for(int re i=1;i<=n;++i){
		a[i]=getint();
		pos[a[i]]=i;
		ans+=query(1,i-1,a[i],0);
		for(int re j=i;j<=n;j+=lowbit(j))update(root[j],1,n,a[i],1);
	}
	cout<<ans<<"\n";
	for(int re i=1;i<m;++i){
		int val=getint();
		ans-=query(1,pos[val]-1,val,0);
		ans-=query(pos[val]+1,n,val,1);
		cout<<ans<<"\n";
		for(int re j=pos[val];j<=n;j+=lowbit(j))update(root[j],1,n,val,-1);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值