题目

采药人的药田是一个树状结构,每条路径上都种植着同种药材。

采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。

采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。

输入格式

第1行包含一个整数N。

接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。

输出格式

输出符合采药人要求的路径数目。

输入样例

7

1 2 0

3 1 1

2 4 0

5 2 0

6 3 1

5 7 1

输出样例

1

提示

对于100%的数据,N ≤ 100,000。

题解

树上路径计数,联想到点分治

对于分治出来的,每一个子树的根,我们需要找出经过该根的满足条件的路径数

很容易想到,如果对两种权值赋值为-1和1的话,一条路径权值和为0一定是阴阳互补的

先不考虑休息站,如果求阴阳互补的路径数,只需要开一个数组记录各种权值出现的次数【当然由于有负数就加上个n】

对于根的每棵子树统计完时,先与之前统计的计算对答案的贡献,路经长为-x的个数乘以之前为x的个数即可

现在考虑休息站,意味着路径中出现中途已经出现0的情况,既然如此,那么休息站到根的权值和与该点到根的权值和一定相等

开一个数组记录dfs路径上各种权值出现的次数,看看该点到根是否存在这样可以作为休息站的点

这样所有的点就分为有休息站和没有休息站两种,分开组合统计,具体就自行思考吧【看代码也行】

复杂度\(O(nlogn)\)

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 100005,maxm = 200005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
LL ans;
int n,h[maxn],ne = 2;
struct EDGE{int to,nxt,w;}ed[maxm];
inline void build(int u,int v,int w){
ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++;
}
int sum,Siz[maxn],F[maxn],rt,vis[maxn];
void getRT(int u,int f){
Siz[u] = 1; F[u] = 0;
Redge(u) if (!vis[to = ed[k].to] && to != f){
getRT(to,u);
Siz[u] += Siz[to];
F[u] = max(F[u],Siz[to]);
}
F[u] = max(F[u],sum - Siz[u]);
if (F[u] < F[rt]) rt = u;
}
LL A[maxm],AA[maxm],B[maxm],BB[maxm];
int ex[maxm],d[maxn];
void dfs(int u,int f){
int x = d[u] + n;
if (ex[x]) BB[x]++;
else B[x]++;
ex[x]++;
Redge(u) if (!vis[to = ed[k].to] && to != f){
d[to] = d[u] + ed[k].w;
dfs(to,u);
}
ex[x]--;
}
void DFS(int u,int f){
Siz[u] = 1;
Redge(u) if (!vis[to = ed[k].to] && to != f){
DFS(to,u);
Siz[u] += Siz[to];
}
}
void solve(int u){
vis[u] = true;
DFS(u,0);
Redge(u) if (!vis[to = ed[k].to]){
for (int i = 0; i <= Siz[to]; i++)
B[n + i] = B[n - i] = BB[n + i] = BB[n - i] = 0;
d[to] = ed[k].w;
dfs(to,u);
ans += BB[n] + BB[n] * A[n] + B[n] * AA[n] + BB[n] * AA[n] + B[n] * A[n];
for (int i = 1; i <= Siz[to]; i++){
ans += BB[n - i] * A[n + i] + B[n - i] * AA[n + i] + BB[n - i] * AA[n + i];
ans += BB[n + i] * A[n - i] + B[n + i] * AA[n - i] + BB[n + i] * AA[n - i];
}
A[n] += B[n]; AA[n] += BB[n];
for (int i = 1; i <= Siz[to]; i++){
A[n - i] += B[n - i];
AA[n - i] += BB[n - i];
A[n + i] += B[n + i];
AA[n + i] += BB[n + i];
}
}
for (int i = 0; i <= Siz[u]; i++)
A[n - i] = A[n + i] = AA[n - i] = AA[n + i] = 0;
Redge(u) if (!vis[to = ed[k].to]){
sum = Siz[to]; F[rt = 0] = INF;
getRT(to,0);
solve(rt);
}
}
int main(){
n = read(); int a,b,w;
for (int i = 1; i < n; i++){
a = read(); b = read(); w = read();
build(a,b,w ? 1 : -1);
}
sum = n; F[rt = 0] = INF;
getRT(1,0);
solve(rt);
cout << ans << endl;
return 0;
}

BZOJ3697 采药人的路径 【点分治】的更多相关文章

  1. BZOJ3697采药人的路径——点分治

    题目描述 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径 ...

  2. BZOJ3697:采药人的路径(点分治)

    Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药 ...

  3. [bzoj3697]采药人的路径——点分治

    Brief Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天 ...

  4. 【BZOJ3697】采药人的路径 点分治

    [BZOJ3697]采药人的路径 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是 ...

  5. [bzoj3697]采药人的路径_点分治

    采药人的路径 bzoj-3697 题目大意:给你一个n个节点的树,每条边分为阴性和阳性,求满足条件的链的个数,使得这条链上阴性的边的条数等于阳性的边的条数,且这条链上存在一个节点,这个节点到一个端点的 ...

  6. bzoj千题计划248:bzoj3697: 采药人的路径

    http://www.lydsy.com/JudgeOnline/problem.php?id=3697 点分治 路径0改为路径-1 g[i][0/1] 和 f[i][0/1]分别表示当前子树 和 已 ...

  7. BZOJ3697: 采药人的路径(点分治)

    Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动 ...

  8. 2019.01.09 bzoj3697: 采药人的路径(点分治)

    传送门 点分治好题. 题意:给出一棵树,边分两种,求满足由两条两种边数相等的路径拼成的路径数. 思路: 考虑将边的种类转化成边权−1-1−1和111,这样就只用考虑由两条权值为000的路径拼成的路径数 ...

  9. BZOJ 3697/3127 采药人的路径 (点分治)

    题目大意: 从前有一棵无向树,树上边权均为$0$或$1$,有一个采药人,他认为如果一条路径上边权为$0$和$1$的边数量相等,那么这条路径阴阳平衡.他想寻找一条合法的采药路径,保证阴阳平衡.然后他发现 ...

随机推荐

  1. PAT (Basic Level) Practise (中文)- 1011. A+B和C (15)

    http://www.patest.cn/contests/pat-b-practise/1011 给定区间[-231, 231]内的3个整数A.B和C,请判断A+B是否大于C. 输入格式: 输入第1 ...

  2. C#4.0中的dynamic关键字和ExpandoObject对象

    dynamic最大的特点我想莫过于在它的类型在运行时才确定,这也是它与往静态类型关键字的最大区别.如果你在你的代码操作中用到了dynamic关键字去定义一个变量时,那么这个变量在编译的时候编译器不会对 ...

  3. HTML5<section>元素

    HTML5<section>元素用来定义页面文档中的逻辑区域或内容的整合(section,区域),比如章节.页眉.页脚或文档中的其他部分. 根据W3C HTML5文档中:section里面 ...

  4. FMDB中的数据处理

    [self.db executeUpdate:@"create table test (a text, b text, c integer, d double, e double)" ...

  5. NOIP模拟赛 混合图

    [题目描述] Hzwer神犇最近又征服了一个国家,然后接下来却也遇见了一个难题. Hzwer的国家有n个点,m条边,而作为国王,他十分喜欢游览自己的国家.他一般会从任意一个点出发,随便找边走,沿途欣赏 ...

  6. python列表之append与extend方法比较

    append和extend是列表的两种添加元素方式,但这两种方式却又有些不同之处.那么不同之处在哪里呢,我们通过对二者的定义和实例来看一看. list.append() 1.定义:L.append(o ...

  7. pythonnet-网络编程(1)

    python的网络编程有不少难点,也容易忘记,最近我会陆续发出系统.完整pythonnet知识的博客,一边复习一边分享,感兴趣的可以关注我. 话不多说,开始吧. 网络编程 目的:数据的传输 ISO(国 ...

  8. java的重载(overload) (2013-10-11-163 写的日志迁移

    有以下几点: 1.方法名相同. 2.方法的 参数类型.个数.顺序至少有一项不同. 3.方法的返回类型可以不同. 4.方法的修饰符可以不同. 5.仅返回类型和修饰符不同也不可以构成重载.   ----- ...

  9. Selenium2用最简xpath查找元素

    什么是xpath? 来自百度百科的解释:XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言.XPath基于XML的树状结构,提供在数据结构树中找寻节点 ...

  10. HDU 5239 Doom 线段树

    题意: 有\(n(1 \leq n \leq 10^5)\)个数,和\(m(1 \leq m \leq 10^5)\)操作,和一个计算\(s\),一切运算都在模\(MOD\)进行的. 操作\(l, \ ...