LG1393 动态逆序对

问题描述

LG1393


题解

本题可以使用(mathrm{CDQ})分治完成。


二维偏序

根据偏序的定义,逆序对是一个二维偏序,但这个二维偏序比较特殊:

  • (i>j,a_i<a_j)

  • (i<j,a_i>a_j)

以上两种情况都符合这个二维偏序。


三维偏序

但带修改二维偏序怎么做?

我们将删除操作视为插入操作。

则没有没删除的插入时间为(1),第(i)个被删除的,插入时间为(m-i+2)

将插入时间作为第一维,数列位置为第二维,数值为第三维。

做三维偏序即可。

注意由于逆序对的定义,三维偏序仍是两种情况。


(mathrm{CDQ})分治

简要介绍一下(mathrm{CDQ})分治。

(mathrm{CDQ})分治是一种分治算法(废话),是一个叫做陈丹琪的女选手在(2009)(记不清了)年提出的。当时提出时是用于优化一类(mathrm{DP})问题的。后来(mathrm{CDQ})分治被主要用于解决三维偏序问题。

(mathrm{CDQ})分治思想类似于归并排序。归并排序每次将区间([l,r])划分为([l, lfloorfrac{l+r}{2} floor])([lfloor frac{l+r}{2} floor + 1,r])

考虑三维偏序问题模型,(i)(j)有贡献需要满足(a_i<a_j,b_i<b_j,c_i<c_j)

(mathrm{CDQ})分治先将(a)升序排序,再进行归并排序,使(b)有序。

考虑区间([l,r]),当完成左右区间的归并排序后,由于一开始先对(a)进行了排序,则(forall x in[l, lfloorfrac{l+r}{2} floor],forall y in [lfloor frac{l+r}{2} floor + 1,r]),一定有(a_x<a_y),这时候分别维护左区间和右区间指针,同时用树状数组维护值即可。

具体请见【模板】三维偏序(陌上花开)题解区。


(mathrm{code})

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,tmp;
struct node{
	int a,b,c,ans;
}a[40007];
int anss[40007];
template<typename Tp>
void read(Tp &x){
	x=0;char ch=1;int fh;
	while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
	if(ch=='-'){
		ch=getchar();fh=-1;
	}
	else fh=1;
	while(ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+ch-'0';
		ch=getchar();
	}
	x*=fh;
}

struct BIT{
	int c[40007];
	void change(int p,int k){
		while(p<=40000){
			c[p]+=k;p+=(p&(-p));
		}
	}
	int query(int p){
		int re=0;
		while(p){
			re+=c[p];p-=(p&(-p));
		}
		return re;
	}
}T;

bool comp(node a,node b){
	if(a.a!=b.a) return a.a<b.a;
	if(a.b!=b.b) return a.b<b.b;
	return a.c<b.c;
}

bool cmp(node a,node b){
	if(a.b!=b.b) return a.b<b.b;
	return a.c<b.c;
}

bool fuck(node a,node b){
	if(a.b!=b.b) return a.b>b.b;
	return a.c>b.c;
}

void cdq(int l,int r){
	if(l==r) return;
	int mid=(l+r)>>1;
	cdq(l,mid);cdq(mid+1,r);
	sort(a+l,a+mid+1,cmp);sort(a+mid+1,a+r+1,cmp);
	int i,j=l,tot=0;
	for(i=mid+1;i<=r;i++){
		while(j<=mid&&a[j].b<=a[i].b){
			T.change(a[j].c,1);++j;++tot;
		}
		a[i].ans+=tot-T.query(a[i].c);
	}
	for(i=l;i<j;i++) T.change(a[i].c,-1);
	sort(a+l,a+mid+1,fuck);sort(a+mid+1,a+r+1,fuck);
	for(i=mid+1,j=l;i<=r;i++){
		while(j<=mid&&a[j].b>=a[i].b){
			T.change(a[j].c,1);++j;
		}
		a[i].ans+=T.query(a[i].c);
	}
	for(i=l;i<j;i++) T.change(a[i].c,-1);
}

bool fake(node a,node b){
	return a.c<b.c;
}

void lsh(){
	sort(a+1,a+n+1,fake);
	for(register int i=1;i<=n;i++) a[i].c=i;
}

signed main(){
	read(n);read(m);
	for(register int i=1;i<=n;i++){
		read(a[i].c);a[i].a=1,a[i].b=i;
	}
	for(register int i=1;i<=m;i++){
		read(tmp);a[tmp].a=m-i+2;
	}
	lsh();
	sort(a+1,a+n+1,comp);
	cdq(1,n);
	for(register int i=1;i<=n;i++) anss[a[i].a]+=a[i].ans;
	for(int i=1;i<=n;i++)anss[i]+=anss[i-1];
	for(int i=m+1;i>0;i--)printf("%lld%c",anss[i]," 
"[i==1]);
	return 0;
}
原文地址:https://www.cnblogs.com/liubainian/p/11503572.html