【BZOJ3295】动态逆序对

题意

\(1\)\(n\) 的一个排列,按照某种顺序依次删除 \(m\) 个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

题解

将操作离线反转,将删除操作看做插入操作。

设一个点 \(i\) 的位置为 \(p_i\), 插入的时间为 \(t_i\), 权值为 \(w_i\) , 那么 \(i\) 的贡献即为 \(\sum_j [t_j<t_i,p_j<p_i,w_j>w_i]+\sum_j [t_j>t_i,p_j>p_i,w_j<w_i]\) .

我们发现这就是一个裸的三维偏序问题,直接用 cdq 做就可以了!

#include<cstdio>
#include<algorithm>
using namespace std;
inline int gi()
{
	char c; int x=0;
	for(;c<'0'||c>'9';c=getchar());
	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
	return x;
}
const int N=100005;
struct node {
	int x,y,id;
} q[N],tmp[N];
bool cmp1(node s, node t) {
	return s.id<t.id;
}
bool cmp2(node s, node t) {
	if(s.x!=t.x) return s.x<t.x;
	if(s.y!=t.y) return s.y<t.y;
	return s.id<t.id;
}
int n,m,a[N],pos[N];
long long ans[N],t[N];
bool vis[N];
#define lowbit(x) (x&-x)
void upd(int i, int w) {
	for(;i<=n;i+=lowbit(i)) t[i]+=w;
}
int qry(int i) {
	int r=0;
	for(;i;i-=lowbit(i)) r+=t[i];
	return r;
}
void cdq(int l, int r)
{
	if(l==r) return ;
	int mid=l+r>>1;
	cdq(l,mid),cdq(mid+1,r);
	sort(q+l,q+mid+1,cmp2);
	sort(q+mid+1,q+r+1,cmp2);
	int j=l;
	for(int i=mid+1;i<=r;++i)
	{
		for(;j<=mid&&q[j].x<q[i].x;++j) upd(q[j].y,1);
		ans[q[i].id]+=qry(n)-qry(q[i].y);
	}
	for(--j;j>=l;--j) upd(q[j].y,-1);
	j=mid;
	for(int i=r;i>mid;--i)
	{
		for(;j>=l&&q[j].x>q[i].x;--j) upd(q[j].y,1);
		ans[q[i].id]+=qry(q[i].y);
	}
	for(++j;j<=mid;++j) upd(q[j].y,-1);
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("1859.in","r",stdin);
#endif
	n=gi(),m=gi();
	for(int i=1;i<=n;++i) a[i]=gi(),pos[a[i]]=i;
	int cnt=n;
	for(int i=1;i<=m;++i)
	{
		int x=gi();
		q[i]=(node){pos[x],x,cnt--};
		vis[x]=true;
	} int mm=m;
	for(int i=1;i<=n;++i)
		if(!vis[a[i]]) q[++mm]=(node){i,a[i],cnt--};
	sort(q+1,q+1+n,cmp1);
	cdq(1,n);
	for(int i=1;i<=n;++i) ans[i]+=ans[i-1];
	for(int i=n;i>n-m;--i) printf("%lld\n",ans[i]);
}
posted @ 2019-02-24 13:00  x_faraway_x  阅读(93)  评论(0编辑  收藏  举报