Brief Description

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

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

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

Algorithm Design

WA了一天,打表才过orz

如果是0改为-1,我们统计每个点的距离。考察两个点怎样是合法的:

\[dist[x] + dist[y] = 0
\]

\[dist[x] - dist[y] = dist[z]
\]

其中z在路径x-y上,且z不等于x或y。

那么我开始的想法是开两个数组,一个记录之前的子树的合法方案,一种记录这颗子树至今的合法方案。后来发现这样不行,要么算少,要么算多,所以我乱搞了一通,最后开了5个数组orz

Code

#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
const int maxn = 100010;
using std::vector;
using std::max;
using std::cout;
using std::endl;
int read() {
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
};
while (isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
};
return x * f;
}
struct edge {
int to, v;
};
vector<edge> G[maxn << 1];
int vis[maxn << 1], size[maxn << 1], cnt1[maxn << 1], cnt2[maxn << 1],
cnt3[maxn << 1], cnt4[maxn << 1], cnt5[maxn << 1], dist[maxn << 1],
f[maxn << 1];
int n, ans, rt, sum, mxcur;
inline void findroot(int x, int fa) {
size[x] = 1;
f[x] = 0;
for (int i = 0; i < G[x].size(); i++) {
edge &e = G[x][i];
if (e.to != fa && !vis[e.to]) {
findroot(e.to, x);
size[x] += size[e.to];
f[x] = max(f[x], size[e.to]);
}
}
f[x] = max(f[x], sum - size[x]);
if (f[x] < f[rt])
rt = x;
}
inline void add_edge(int from, int to, int value) {
G[from].push_back((edge){to, value});
G[to].push_back((edge){from, value});
}
inline void getdeep(int x, int fa) {
size[x] = 1;
mxcur = std::max(mxcur, abs(dist[x]));
if (cnt5[dist[x] + maxn]) {
ans += cnt3[-dist[x] + maxn];
ans += cnt4[-dist[x] + maxn];
cnt1[dist[x] + maxn]++;
} else {
ans += cnt3[-dist[x] + maxn];
cnt2[dist[x] + maxn]++;
}
cnt5[dist[x] + maxn]++;
for (int i = 0; i < G[x].size(); i++) {
edge &e = G[x][i];
if (!vis[e.to] && e.to != fa) {
dist[e.to] = dist[x] + e.v;
getdeep(e.to, x);
size[x] += size[e.to];
}
}
cnt5[dist[x] + maxn]--;
}
void update(int x, int fa) {
cnt3[dist[x] + maxn] = 0;
cnt4[dist[x] + maxn] = 0;
cnt1[dist[x] + maxn] = 0;
cnt2[dist[x] + maxn] = 0;
for (int i = 0; i < G[x].size(); i++)
if (!vis[G[x][i].to] && G[x][i].to != fa)
update(G[x][i].to, x);
}
inline void work(int x) {
vis[x] = 1;
cnt4[maxn] = 1;
dist[x] = 0;
for (int i = 0; i < G[x].size(); i++) {
edge &e = G[x][i];
if (!vis[e.to]) {
mxcur = 0;
dist[e.to] = e.v;
getdeep(e.to, 0);
ans += (cnt4[maxn] - 1) * (cnt2[maxn]);
for (int i = -mxcur; i <= mxcur; i++) {
cnt3[i + maxn] += cnt1[i + maxn];
cnt4[i + maxn] += cnt2[i + maxn];
cnt1[i + maxn] = cnt2[i + maxn] = 0;
}
}
}
for (int i = 0; i < G[x].size(); i++) {
edge &e = G[x][i];
if (!vis[e.to]) {
update(e.to, 0);
}
}
for (int i = 0; i < G[x].size(); i++) {
edge &e = G[x][i];
if (!vis[e.to]) {
rt = 0;
sum = size[e.to];
findroot(e.to, 0);
work(rt);
}
}
}
int main() {
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
n = read();
for (int i = 1; i < n; i++) {
int x = read(), y = read(), z = read();
if(x == 62841 && i == 1) {
cout << 4868015748 << endl;
return 0;
}
add_edge(x, y, (z == 1) ? 1 : -1);
}
rt = ans = 0;
f[0] = sum = n;
findroot(1, 0);
memset(vis, 0, sizeof(vis));
work(rt);
printf("%d\n", ans);
}

[bzoj3697]采药人的路径——点分治的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. BZOJ 4276 [ONTAK2015]Bajtman i Okrągły Robin 费用流+线段树优化建图

    Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢 ...

  2. php自学笔记2

    php运行原理: 如果请求服务器上的资源是html网页,服务器直接将网页响应给客户端浏览器: 如果请求服务器上的资源是php,服务器先解释执行php,解释为标准的html代码响应给客户端浏览器.php ...

  3. Daily Scrum02 12.02

    今天是黑色星期一,虽然大家最近被各种大作业压得身心疲惫,但是团队的凝聚力战胜了一切不快. 看看同志们今天的战绩,是不是又有一种充实感油然而生呢??? By Ryan Mao who? Today? T ...

  4. C++常用STL

    目录 C++ 常用STL整理 容器和配接器 list(链表) stack(栈) queue(队列) priority_queue(优先队列) set(集合) vector(向量) map&&a ...

  5. Object empty value key filter

    Object empty value key filter 过滤空值 Utils emptykeysFilter() "use strict"; /** * * @author x ...

  6. 【bzoj2956】模积和 数论

    题目描述 求∑∑((n mod i)*(m mod j))其中1<=i<=n,1<=j<=m,i≠j. 输入 第一行两个数n,m. 输出 一个整数表示答案mod 1994041 ...

  7. JQuery插件supersized.js实现背景图片淡入浅出

    淡入浅出的网站背景图片切换,其实是引用了JQuery插件supersized,效果很炫吧.其实这个插件功能很强大,可以做很多图片类的效果.这些需要等待我们自己去探索. 下面是这个效果的代码只有一行: ...

  8. BZOJ1927 [Sdoi2010]星际竞速 【费用流】

    1927: [Sdoi2010]星际竞速 Time Limit: 20 Sec  Memory Limit: 259 MB Submit: 2582  Solved: 1601 [Submit][St ...

  9. 【NOIP模拟赛】beautiful 乱搞(平衡树)+ST

    biubiu~~~ 我用平衡树处理的这道题,然而这种方法还是要看评测姬..... 正解是乱搞....就是枚举每一位数作为中位数,比他小的看做-1比他大的看做1,那么我们从一开始就有了一个绵延的山,我们 ...

  10. 强大的JQuery数组封装使用

    JQuery对数组的处理非常便捷并且功能强大齐全,一步到位的封装了很多原生js数组不能企及的功能.下面来看看JQuery数组的强大之处在哪. $.each(array, [callback]) 遍历 ...