3697: 采药人的路径
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 407 Solved: 147
[ Submit][ Status][ Discuss]
Description
采药人的药田是一个树状结构,每条路径上都种植着同种药材。
采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。
Input
第1行包含一个整数N。
接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。
Output
输出符合采药人要求的路径数目。
Sample Input
7
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
Sample Output
1
HINT
对于100%的数据,N ≤ 100,000。
解题思路:树分治。hzwer的讲解。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define inf 1000000000
#define ll long long
using
namespace
std
;
inline
int
read
(
)
{
int
x
=
0
,
f
=
1
;
char
ch
=
getchar
(
)
;
while
(
ch
<
'0'
||
ch
>
'9'
)
{
if
(
ch
==
'-'
)
f
=
-
1
;
ch
=
getchar
(
)
;
}
while
(
ch
>=
'0'
&&
ch
<=
'9'
)
{
x
=
x
*
10
+
ch
-
'0'
;
ch
=
getchar
(
)
;
}
return
x
*
f
;
}
int
n
,
cnt
,
sum
,
rt
,
mxdeep
;
bool
vis
[
200005
]
;
int
t
[
200005
]
,
mx
[
100005
]
,
fa
[
100005
]
,
size
[
100005
]
,
deep
[
100005
]
,
dis
[
100005
]
;
ll
ans
,
g
[
200005
]
[
2
]
,
f
[
200005
]
[
2
]
;
struct
edge
{
int
to
,
next
,
v
;
}
e
[
200005
]
;
int
last
[
100005
]
;
void
insert
(
int
u
,
int
v
,
int
w
)
{
e
[
++
cnt
]
.
to
=
v
;
e
[
cnt
]
.
next
=
last
[
u
]
;
last
[
u
]
=
cnt
;
e
[
cnt
]
.
v
=
w
;
e
[
++
cnt
]
.
to
=
u
;
e
[
cnt
]
.
next
=
last
[
v
]
;
last
[
v
]
=
cnt
;
e
[
cnt
]
.
v
=
w
;
}
void
getroot
(
int
x
,
int
fa
)
{
size
[
x
]
=
1
;
mx
[
x
]
=
0
;
for
(
int
i
=
last
[
x
]
;
i
;
i
=
e
[
i
]
.
next
)
if
(
e
[
i
]
.
to
!=
fa
&&
!
vis
[
e
[
i
]
.
to
]
)
{
getroot
(
e
[
i
]
.
to
,
x
)
;
size
[
x
]
+=
size
[
e
[
i
]
.
to
]
;
mx
[
x
]
=
max
(
mx
[
x
]
,
size
[
e
[
i
]
.
to
]
)
;
}
mx
[
x
]
=
max
(
mx
[
x
]
,
sum
-
size
[
x
]
)
;
if
(
mx
[
x
]
<
mx
[
rt
]
)
rt
=
x
;
}
void
dfs
(
int
x
,
int
fa
)
{
mxdeep
=
max
(
mxdeep
,
deep
[
x
]
)
;
if
(
t
[
dis
[
x
]
]
)
f
[
dis
[
x
]
]
[
1
]
++
;
else
f
[
dis
[
x
]
]
[
0
]
++
;
t
[
dis
[
x
]
]
++
;
for
(
int
i
=
last
[
x
]
;
i
;
i
=
e
[
i
]
.
next
)
if
(
e
[
i
]
.
to
!=
fa
&&
!
vis
[
e
[
i
]
.
to
]
)
{
deep
[
e
[
i
]
.
to
]
=
deep
[
x
]
+
1
;
dis
[
e
[
i
]
.
to
]
=
dis
[
x
]
+
e
[
i
]
.
v
;
dfs
(
e
[
i
]
.
to
,
x
)
;
}
t
[
dis
[
x
]
]
--
;
}
void
cal
(
int
x
)
{
int
mx
=
0
;
vis
[
x
]
=
1
;
g
[
n
]
[
0
]
=
1
;
for
(
int
i
=
last
[
x
]
;
i
;
i
=
e
[
i
]
.
next
)
if
(
!
vis
[
e
[
i
]
.
to
]
)
{
dis
[
e
[
i
]
.
to
]
=
n
+
e
[
i
]
.
v
;
deep
[
e
[
i
]
.
to
]
=
1
;
mxdeep
=
1
;
dfs
(
e
[
i
]
.
to
,
0
)
;
mx
=
max
(
mx
,
mxdeep
)
;
ans
+=
(
g
[
n
]
[
0
]
-
1
)
*
f
[
n
]
[
0
]
;
for
(
int
j
=
-
mxdeep
;
j
<=
mxdeep
;
j
++
)
ans
+=
g
[
n
-
j
]
[
1
]
*
f
[
n
+
j
]
[
1
]
+
g
[
n
-
j
]
[
0
]
*
f
[
n
+
j
]
[
1
]
+
g
[
n
-
j
]
[
1
]
*
f
[
n
+
j
]
[
0
]
;
for
(
int
j
=
n
-
mxdeep
;
j
<=
n
+
mxdeep
;
j
++
)
{
g
[
j
]
[
0
]
+=
f
[
j
]
[
0
]
;
g
[
j
]
[
1
]
+=
f
[
j
]
[
1
]
;
f
[
j
]
[
0
]
=
f
[
j
]
[
1
]
=
0
;
}
}
for
(
int
i
=
n
-
mx
;
i
<=
n
+
mx
;
i
++
)
g
[
i
]
[
0
]
=
g
[
i
]
[
1
]
=
0
;
for
(
int
i
=
last
[
x
]
;
i
;
i
=
e
[
i
]
.
next
)
if
(
!
vis
[
e
[
i
]
.
to
]
)
{
sum
=
size
[
e
[
i
]
.
to
]
;
rt
=
0
;
getroot
(
e
[
i
]
.
to
,
0
)
;
cal
(
rt
)
;
}
}
int
main
(
)
{
n
=
read
(
)
;
for
(
int
i
=
1
;
i
<
n
;
i
++
)
{
int
u
=
read
(
)
,
v
=
read
(
)
,
w
=
read
(
)
;
if
(
!
w
)
w
=
-
1
;
insert
(
u
,
v
,
w
)
;
}
sum
=
mx
[
0
]
=
n
;
getroot
(
1
,
0
)
;
cal
(
rt
)
;
printf
(
"%lld"
,
ans
)
;
return
0
;
}