CF785E Anton and Permutation

CF785E Anton and Permutation

CF785E Anton and Permutation

带交换逆序对。

前面(位置)比它大的数的个数+后面比它小的个数,很显然这就是一个三维偏序的问题(时间上也要满足偏序)

首先把第一维时间排序(原本就有序了)

然后对位置进行CDQ分治,对右半部分计算左半部分:位置在其左边值大,位置在其右边值小的方案

注意:左右两半部分在位置上是独立有序的,在计算时还要看另一边是否满足位置上的限制

这样就能得到当前区间,每一个操作对应的逆序对,如果是插入,对应答案就加上,如果是删除,就剪掉

注意上面的这一个过程,其实只是单独考虑每个操作对答案的影响,最后还要把答案求个前缀和

cdq分治题解代码:

view code
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int N=2e5+10,M=5e4+10;
int n;
int val[N],t[N];
ll ans[M];
struct node
{
	int a,b,c;
	int type,id;
}v[N+4*M],w[N+4*M];
inline int lowbit(int x)
{
	return x&(-x);
}
inline void change(int x,int c)
{
	for(int i=x;i<=n;i+=lowbit(i))
		t[i]+=c;
}
inline int query(int x)
{
	int res=0;
	for(int i=x;i>=1;i-=lowbit(i))
		res+=t[i];
	return res;
}
inline void CDQ(int l,int r)
{
	if(l==r) return;
	int mid=(l+r)/2,p,q;
	CDQ(l,mid),CDQ(mid+1,r);
	p=l,q=mid+1;
	while(q<=r)//计算左边位置小值大 
	{
		while(p<=mid&&v[p].b<=v[q].b) change(v[p].c,v[p].type),p++;
		ans[v[q].id]+=v[q].type*(query(n)-query(v[q].c)),q++;
	}
	for(int i=l;i<p;i++) change(v[i].c,-v[i].type);
	p=mid,q=r;
	while(q>mid)//计算左边位置大值小 
	{
		while(p>=l&&v[p].b>=v[q].b) change(v[p].c,v[p].type),p--;
		ans[v[q].id]+=v[q].type*query(v[q].c-1),q--;
	}
	for(int i=mid;i>p;i--) change(v[i].c,-v[i].type);
	p=l,q=mid+1;
	for(int i=l;i<=r;i++)//归并排序
	{
		if((p<=mid&&v[p].b<=v[q].b)||q>r) w[i]=v[p++];
		else w[i]=v[q++];
	} 
	for(int i=l;i<=r;i++) v[i]=w[i];
}
int main()
{
	int m,tot=0,a,b;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		val[i]=i,v[++tot]=(node){tot,i,i,1,0};
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&a,&b);
		v[++tot]=(node){tot,a,val[a],-1,i};
		v[++tot]=(node){tot,b,val[b],-1,i};
		v[++tot]=(node){tot,a,val[b],1,i};
		v[++tot]=(node){tot,b,val[a],1,i};
		swap(val[a],val[b]);
	}
	CDQ(1,tot);
	for(int i=1;i<=m;i++)
		ans[i]+=ans[i-1];
	for(int i=1;i<=m;i++)
		printf("%lld
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/Akmaey/p/14648581.html