Luogu P1393 动态逆序对

戳我看题面

常规操作:离线后删除改成插入(倒着做)

问题就变成了插入一个数,求逆序对

求逆序对是cdq分治,所以插入一个数求逆序对多半也是cdq分治

构造三元组(a,b,c)a表示时间,b表示位置,c表示数的大小

新插入一个数j带来的影响无疑是       \sum_{i=1}^{j-1}   a_{i}<a_{j}且(b_{i}<b_{j}c_{i}>c_{j}或者b_{i}>b_{j},c_{i}<c_{j}) 

记下来后求一前缀和就搞定了

#include<cstdio>
#define ll long long
using namespace std;

const int N=1e6+5;
int n,m,t[N],c,a[N];
bool f[N];
ll ans[N];
struct A{int id,a,b,c; }qq[N],q[N],q1[N],q2[N];

void work2(int l,int r)
{
	if(l==r) return;
	int mid=l+r>>1;
	work2(l,mid),work2(mid+1,r);
	int i=l,j=mid+1,k=l,y=0;
	for(int i=l;i<=mid;i++)
		if(q1[i].a==0) y++;
	while(i<=mid&&j<=r)
	{
		if(q1[i].c<=q1[j].c) 
		{
			if(q1[i].a==0) y--;
			q2[k++]=q1[i++];
		} else 
		{
			if(q1[j].a==1) ans[q1[j].id]+=y;
			q2[k++]=q1[j++];
		}
	}
	while(i<=mid) q2[k++]=q1[i++];
	while(j<=r) q2[k++]=q1[j++];
	for(int i=l;i<=r;i++) q1[i]=q2[i];
}

void work1(int l,int r)
{
	if(l==r) return;
	int mid=l+r>>1;
	work1(l,mid),work1(mid+1,r);
	int i=l,j=mid+1,k=l;
	while(i<=mid&&j<=r)
	{
		if(q[i].b<=q[j].b) q[i].a=0,q1[k++]=q[i++];
			else q[j].a=1,q1[k++]=q[j++];
	}
	while(i<=mid) q[i].a=0,q1[k++]=q[i++];
	while(j<=r) q[j].a=1,q1[k++]=q[j++];
	for(int i=l;i<=r;i++) q[i]=q1[i];
	work2(l,r);
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]); 
	c=n;
	for(int i=1;i<=m;i++) 
	{
		int x; scanf("%d",&x); 
		qq[c]=(A){i-1,c,x,a[x]}; f[x]=1;
		c--; 
	}
	for(int i=1;i<=n;i++)
		if(!f[i]) qq[c]=(A){m,c,i,a[i]},c--;
	for(int i=1;i<=n;i++) q[i]=qq[i];
	work1(1,n);	
	for(int i=1;i<=n;i++) 
		q[i].id=qq[i].id,q[i].a=qq[i].a,q[i].b=qq[i].c,q[i].c=qq[i].b;
	work1(1,n);
	for(int i=m-1;i>=0;i--) ans[i]+=ans[i+1];
	for(int i=0;i<=m;i++) 
		printf("%lld%c",ans[i],(i==m)?'\n':' ');
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/YYHS_WSF/article/details/84727576