Gym - 101485G NWERC2015 G Guessing Camels

本文介绍了一种解决三维偏序问题的方法,通过使用树状数组统计逆序对,并结合CDQ分治思想来求解。文章详细解释了如何通过对比三个数列中每对数字的相对位置来判断是否符合三维偏序条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本题暴力做听说可以动态树,然而我不会。

3维偏序可以用CDQ分治,寒假学了然而考场上不会写。(菜不成声.jpg)

再间接一点,我们知道是用总数对减去存在逆序的数对。

而逆序就是求两个数列中的两个数字相对位置是反的。

如果我们队(a,b)(b,c)(a,c)都进行求逆序对。在三维中,只要满足一对与另外两对相对顺序不同即是不符合的。

一对数字不符合正序的在这样的统计中会对cnt贡献2次,那么就ans=C(n,2)-cnt/2

判断两个数列中一对数字相对顺序不同的方法是,先用d[x]=i存储x在A数组中所在的位置是i

在对B数组用归并排序或者树状数组统计,i-1-sum(d[B[i]]),即B数组的前i-1个数字在A数组对应有多少在d[B[i]]后面的。

cdq分治的坑留着以后补QAQ

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxl 200010

int n;
int aa[maxl],bb[maxl],cc[maxl],b[maxl],d[maxl];
long long ans;

inline void prework()
{
	ans=0;
	for(int i=1;i<=n;i++)
		scanf("%d",&aa[i]);
	for(int i=1;i<=n;i++)
		scanf("%d",&bb[i]);
	for(int i=1;i<=n;i++)
		scanf("%d",&cc[i]);
}

inline int sum(int i)
{
	int s=0;
	while(i)
	{
		s+=b[i];
		i-=i&-i;
	}
	return s;
}

inline void add(int i,int x)
{
	if(i==0) return;
	while(i<maxl)
	{
		b[i]+=x;
		i+=i&-i;
	}
}

inline void mainwork()
{
	for(int i=1;i<=n;i++)
		d[aa[i]]=i;
	memset(b,0,sizeof(b));
	for(int i=1;i<=n;i++)
	{
		ans+=i-1-sum(d[bb[i]]);
		add(d[bb[i]],1);
	}
	for(int i=1;i<=n;i++)
		d[bb[i]]=i;
	memset(b,0,sizeof(b));
	for(int i=1;i<=n;i++)
	{
		ans+=i-1-sum(d[cc[i]]);
		add(d[cc[i]],1);
	}
	for(int i=1;i<=n;i++)
		d[cc[i]]=i;
	memset(b,0,sizeof(b));
	for(int i=1;i<=n;i++)
	{
		ans+=i-1-sum(d[aa[i]]);
		add(d[aa[i]],1);
	}
}

void print()
{
	ans=((long long)n*(n-1)-ans)/2;
	printf("%lld\n",ans);
}

int main()
{
	while(~scanf("%d",&n))
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值