原题链接

题目大意

有$n$个男生和$n$个女生,男生的编号为$1{\sim} n$,女生的编号为$n+1{\sim}2n$
女生坐在第一排,男生坐在第二排。男生的编号从左往右依次递增,现按顺序给出每个男生前面坐着的女生的编号,以及该男生喜欢的女生的编号,求每一对的连线上与其他男女的连线有多少个交点,题目保证每一个男生都有喜欢的女生且每个女生只会被一个男生喜欢。

解题思路

我们可以不看女生的编号,只看女生所在的列号,设男生的列号表示为$x$,女生的列号为$y$,那么每一对互相喜欢的男女可以表示为点对$(x_i,y_i)$,若$(x_i-x_j)*(y_i-y_j)<0$则说明第i对男女生的连线与第j对男女生的连线有交点。
因为男生的列号是有序的,即若$i<j$则必有$x_i<x_j$,所以对于$i<j$的情况我们需要数出$y_i>y_j(j\in[i+1,n])$的情况,也就是y数组的逆序对;同时也需要考虑到与前面的点对的交点,也就是说对于第$i$个数对我们要在$i>j$的部分找$y_i<y_i$的个数,在$i<j$的部分找$y_i>y_j$的个数,求和即是答案。
关于求逆序数的可以用树状数组或是用分治法求得

逆序数的两种求法

AC代码

思路理解了,但是代码太丑了挖个坑睡觉起来重构一遍。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6;
int n;
int a[maxn];
int b[maxn];
int y[maxn];
int c[maxn];
pair<int,int> p1[maxn],p2[maxn];

int lowbit(int x)
{return x&(-x);}
void add(int i,int x)
{
while(i<=n)
{
c[i]+=x;
i+=lowbit(i);
}
}

//返回前x项的和
int sum(int x)
{
int ans=0;
while(x>0)
{
ans+=c[x];
x-=lowbit(x);
}
return ans;
}

int nx_num[maxn];
int zx_num[maxn];
int ans[maxn];
void get_nx(int nx[],pair<int,int> p[])
{
for(int i=1;i<=n;++i)c[i]=0;

for(int i=1;i<=n;++i){
int wz=p[i].second;
add(wz,1);
nx[wz]=sum(wz-1);
}
}

int main(){
cin>>n;

int aa;
for(int i=1;i<=n;i++)
{
cin>>aa>>b[i]; //b[i]表示第i个男生喜欢的女生的编号
a[aa]=i; //a[aa]表示编号为aa的女生所在的列号
}

for(ll i=1;i<=n;++i){
y[i]=a[b[i]]; //y[i]表示第i个男生喜欢的女生所在的列号
p1[i].first=n-y[i]+1;
p1[i].second=i;
p2[n-i+1].first=y[i];
p2[n-i+1].second=n-i+1;
}

sort(p1+1,p1+n+1);
sort(p2+1,p2+1+n);
get_nx(nx_num,p1);
get_nx(zx_num,p2);

for(int i=1;i<=n;i++)
{
ans[i]=nx_num[i]+zx_num[n-i+1];
cout<<ans[i]<<endl;
}

}