本题暴力做听说可以动态树,然而我不会。
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;
}