bzoj 2441 [中山市选2011]小W的问题
bzoj 2441 [中山市选2011]小W的问题
Description
有一天,小W找了一个笛卡尔坐标系,并在上面选取了N个整点。他发现通过这些整点能够画出很多个“W”出来。具体来说,对于五个不同的点(x1, y1), (x2, y2), (x3, y3), (x4, y4), (x5, y5),如果满足:
·x1 < x2 < x3 < x4 < x5
·y1 > y3 > y2
·y5 > y3 > y4
则称它们构成一个“W”形。
现在,小W想统计“W”形的个数,也就是满足上面条件的五元点组个数。你能帮助他吗?
Input
第一行包含一个整数N,表示点的个数。
下面N行每行两个整数,第i+1行为(xi, yi),表示第i个点的坐标。
Output
仅包含一行,为“W”形个数模1 000 000 007的值。
Sample Input
6
1 10
2 1
3 5
4 6
5 1
6 10
Sample Output
3
HINT
对于100%的数据满足N ≤ 200 000,0 ≤ xi ≤ 10^9,0 ≤ yi ≤ 10^9
Solution
第一次做这道题可能是八九个月之前了,当时看题解看了半天,今天重做了一遍,感觉还是细节多到爆炸
NewTrain 里面有好几道这样给定平面上的点计数的问题,套路基本都差不多
首先一个明显的想法就是把 'W' 变成两个 'V'
那么题目转化成求 'V' 形状的个数,并且把他记录在 'V' 的某一个端点上
最后计算答案就是把每个点当做两个 'V' 的公共点求一个答案
现在我们把形状转化成三元组,比如三元组 (1,2,3)表示的是一个三个点上升的形状,就是 x1 < x2 < x3, y1 < y2 < y3,而题目里的三元组就是 (3,1,2) 和 (2,1,3) ,公共点就是 2
两种形状的统计是等价的,所以只讨论把 (3,1,2) 的个数并且记录在 2 上
有一种比较暴力的做法,按照纵坐标排序,每个点上面的数表示未插入的序列(也就是纵坐标比他大的点中横坐标比他小的的点,实际上就是他左上角的点数量),那么以 i 这个位置为 2 的 (3,1,2) 的个数就是他左下角的点对应的数的和,因为现在在未插的数都是大于 i 的纵坐标的。
考虑怎么维护这个东西,计数的过程比较简单,就是树状数组统计插入的点的横坐标及其对应的数。
修改的时候,事实上每插入一个点就会对未插入序列中横坐标比他大的所有点影响,使他们的数减去 1
这种做法比较暴力,而且在有相等坐标的时候细节较多
下面有一种比较精妙的做法
我们考虑(2,1,3) 的个数
很显然不好做,所以考虑容斥
网上说直接用 (?,?,3) - (1,2,3) 就可以了,但是我不明白这样怎么能统计到 2 这个位置上,我觉得这样只能放在 3 上,然后就爆炸了
后来我自己想了一个复杂一点的容斥,考虑当前点是 i,我们将每个点的权值设为这个点的右侧的点的个数,那么考虑 i 右侧所有纵坐标小于 i 的点的权值和 - (3,2,1) - (3,1,2) 就是答案了
这样比第一种做法好写好调得多
综上所述,这题出的纯粹为了恶心人(你说明明会了 'v' 就会 'w',他硬是要你写两遍不同方向的,而且明明可以出成横纵坐标都不相等,可以方便得多)
代码就不附了,比较丑陋