首先我们考虑对于一个点,他的十字架的个数是多少,我们用
l
,
r
,
u
,
d
l,r,u,d
l,r,u,d分别表示他左边,右边,上边,下边的树的个数,那么他的贡献应该是
C
l
k
×
C
r
k
×
C
u
k
×
C
d
k
C_l^k\times C_r^k \times C_u^k \times C_d^k
Clk×Crk×Cuk×Cdk
但是因为这个
n
,
m
n,m
n,m都太大了,但是我们发现树的个数只有
1
0
5
10^5
105,所以我们可以考虑将他们离散化掉
但是离散化了会不会影响答案呢?显然是不会的,因为如果一行上面没有任何常青树一定不会对答案造成任何的贡献。
接下来我们考虑如果求一字型(在他下面找
k
k
k个,上面找
k
k
k个)的个数应该怎么做
应该是
C
u
k
×
C
d
k
C_u^k\times C_d^k
Cuk×Cdk对吧
那么如果是十字型,就应该是
C
u
k
×
C
d
k
×
v
a
l
(
y
)
C_u^k\times C_d^k\times val(y)
Cuk×Cdk×val(y),
v
a
l
(
y
)
val(y)
val(y)表示这一行的贡献
然后我们发现,对于两个点
(
x
,
y
1
)
,
(
x
,
y
2
)
(x,y_1),(x,y_2)
(x,y1),(x,y2),对于任意的点
(
x
,
y
)
(x,y)
(x,y),如果
y
∈
(
y
1
,
y
2
)
y\in(y_1,y_2)
y∈(y1,y2),那么他的上下方向上的答案是不变的,那么我们可以利用
C
u
k
×
C
d
k
×
∑
i
=
y
1
+
1
y
2
−
1
v
a
l
(
i
)
C_u^k\times C_d^k\times \sum_{i=y_1+1}^{y_2-1}val(i)
Cuk×Cdk×∑i=y1+1y2−1val(i)快速的算出这一段的答案
那么我们现在要做的是维护一个区间和,我们可以用树状数组来维护
那么
d
,
u
d,u
d,u怎么求呢?我们可以按
x
x
x为第一关键字,
y
y
y为第二关键字对于每一棵树进行排序,记录
s
u
m
x
i
sumx_i
sumxi表示
x
x
x左边为
i
i
i的点的个数,
d
d
d可以在循环的过程中预处理出来,而
u
=
s
u
m
x
i
−
d
u=sumx_i-d
u=sumxi−d
然后考虑更新答案,我们可以记录
s
u
m
y
i
sumy_i
sumyi表示
y
y
y左边为
i
i
i的点的个数,然后再记录一个
v
i
s
y
i
visy_i
visyi表示
y
y
y坐标为
i
i
i的点已经经过了几次(其实就是
l
l
l),然后就可以更新了
总结一下这道题的几个步骤:
- 对于 x x x, y y y分别离散化(因为要记录 s u m x sumx sumx所以 x x x坐标离散化也是必须的)
- 按 x x x坐标为第一关键字, y y y坐标为第二关键字进行排序
- 利用树状数组维护区间横向一字型的可能情况和
- 扫描每一棵树,记录 u , d u,d u,d算出贡献,同时更新相应的树状数组
我觉得这道题的思考难度主要就在于我们发现离散化之后对答案是 没有影响的
然后后面的都还比较好想吧…