[题目链接]

https://www.lydsy.com/JudgeOnline/problem.php?id=3697

[算法]

首先 , 将黑色的边变成1 ,白色的边变成-1

那么 , 问题就转化为了有多少条路径满足 :

1. 路径长度为0

2. 路径中间存在一个点使得这个点可以将这条路径分成两段且长度为0

考虑我们已经处理完了前面的子树 , 对于当前子树中一点x , 深度为d , 显然 , 前面的子树中要有一个深度为-d的点y ,这条路径合法当且仅当x到分治重心的路径上有一点满足d[z] = d[x]或y到分治重心的路径上有一点满足d[z] = d[y]

那么我们可以记s[i][0 / 1]表示前面的子树中深度为i ,不存在/存在它到当前分治重心路径上的一个点,使得它的深度= i的点的个数

考虑对于当前深度为d的点x,显然至少有s[−d][1]个点会和x形成一条合法的路径。 如果分治重心到x的路径上存在一个深度为d的点,那么还会有s[−d][0]个点会和x形成一条合法路径。

        详见代码 , 时间复杂度 : O(NlogN)

[代码]

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200010
typedef long long LL;
const int inf = 2e9; struct edge
{
int to , w , nxt;
} e[MAXN << ]; int n , tot , root , len;
int head[MAXN] , size[MAXN] , weight[MAXN] , cnt[MAXN << ];
int s[MAXN << ][];
bool visited[MAXN];
LL ans; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
T f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = (x << ) + (x << ) + c - '';
x *= f;
}
inline void addedge(int u,int v,int w)
{
tot++;
e[tot] = (edge){v , w , head[u]};
head[u] = tot;
}
inline void getroot(int u , int fa , int total)
{
weight[u] = ;
size[u] = ;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa || visited[v]) continue;
getroot(v , u , total);
size[u] += size[v];
chkmax(weight[u] , size[v]);
}
chkmax(weight[u] , total - size[u]);
if (weight[u] < weight[root]) root = u;
}
inline void calc(int u , int fa , int dep)
{
ans += s[n - dep][];
if (cnt[n + dep] > ) ans += s[n - dep][];
if (dep == && cnt[n] > ) ++ans;
++cnt[n + dep];
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (v == fa || visited[v]) continue;
calc(v , u , dep + w);
}
--cnt[n + dep];
}
inline void update(int u , int fa , int dep)
{
++s[n + dep][cnt[n + dep] > ];
++cnt[n + dep];
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (v == fa || visited[v]) continue;
update(v , u , dep + w);
}
--cnt[n + dep];
}
inline void clear(int u , int fa , int dep)
{
size[u] = ;
--s[n + dep][cnt[n + dep] > ];
++cnt[n + dep];
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (v == fa || visited[v]) continue;
clear(v , u , dep + w);
size[u] += size[v];
}
--cnt[n + dep];
}
inline void work(int u)
{
visited[u] = true;
cnt[n] = ;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (visited[v]) continue;
calc(v , u , w);
update(v , u , w);
}
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (visited[v]) continue;
clear(v , u , w);
}
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (visited[v]) continue;
root = ;
getroot(v , , size[v]);
work(root);
}
} int main()
{ read(n);
for (int i = ; i < n; i++)
{
int u , v , w;
read(u); read(v); read(w);
w = (w == ) ? - : ;
addedge(u , v , w);
addedge(v , u , w);
}
weight[root = ] = inf;
getroot( , , n);
work(root);
printf("%lld\n",ans); return ; }

[BZOJ 3697] 采药人的路径的更多相关文章

  1. BZOJ 3697: 采药人的路径 [点分治] [我想上化学课]

    传送门 题意: 路径有$-1,1$两种权值,求有多少路径满足权值和为$0$且有一个点将路径分成权值和为$0$的两段 第四节课本来想去上化学,然后快上课了这道题还没调出来.....可恶我想上化学 昨天两 ...

  2. bzoj 3697: 采药人的路径【点分治】

    点分治,设当前处理的块的重心为rt,预处理出每个子树中f[v][0/1]表示组合出.没组合出一对值v的链数(从当前儿子出发的链),能组合出一对v值就是可以有一个休息点 然后对于rt,经过rt且合法的路 ...

  3. BZOJ 3697: 采药人的路径 点分治

    好久不做点分治的题了,正好在联赛之前抓紧复习一下. 先把边权为 $0$ 的置为 $-1$.定义几个状态:$f[dis][0/1],g[dis][0/1]$ 其中 $f$ 代表在当前遍历的子树内的答案. ...

  4. 【BZOJ】3697: 采药人的路径

    3697: 采药人的路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1718  Solved: 602[Submit][Status][Discu ...

  5. 【BZOJ】【3697】采药人的路径&【3127】【USACO2013 Open】Yin and Yang

    点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. ...

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

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

  7. 【BZOJ-3697&3127】采药人的路径&YinandYang 点分治 + 乱搞

    3697: 采药人的路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 681  Solved: 246[Submit][Status][Discus ...

  8. BZOJ3697: 采药人的路径

    传送门 不是那么裸的点分治. $f[i][0/1]$表示当前节点的一个子树中总权值和为$i$,且是否存在一个前缀使得其前缀和为$i$ $g[i][0/1]$表示当前节点的已遍历过的子树,其余一样. 对 ...

  9. BZOJ_3697_采药人的路径_点分治

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

随机推荐

  1. R必学包之dplyr

    http://www.360doc.com/content/17/1204/10/50223086_709726679.shtml

  2. PAT (Advanced Level) 1086. Tree Traversals Again (25)

    入栈顺序为先序遍历,出栈顺序为中序遍历. #include<cstdio> #include<cstring> #include<cmath> #include&l ...

  3. 安装ubuntu 12.04 后遇到的问题

    我的笔记本是08年的戴尔,比较老的机子了.给本本安装ubuntu/windows8双系统后,ubuntu系统中出现了一些问题,在网上搜寻许多解决方法,管用的就分享一下,顺便做一下记录,免得下次自己又不 ...

  4. JDBC自定义连接池

    开发中,"获得连接"和"释放资源"是非常消耗系统资源的,为了解决此类性能问题可以采用连接池技术来共享连接Connection. 1.概述 用池来管理Connec ...

  5. Android 学习笔记---获取RadioGroup的选定值

    1,获取RadioGroup控件: RadioGroup radioGroup = (RadioGroup)findViewById(R.id.myRadioGroup); 2,获取RadioButt ...

  6. js上传文件研究

    https://github.com/shengulong/javascript-file-upload

  7. Qt5官方demo解析集30——Extending QML - Binding Example

    本系列全部文章能够在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集29--Extendin ...

  8. "听话"的品格的症状

    反思了一下,也许是因为以前比较听话,听大人的话,听老师的话,听长辈的话.听电视剧的话..........哈哈 现在发现,世界是靠自己去认识,去体会的,别人的经验都只能作为参考,绝对不能不加思考的照搬硬 ...

  9. Multiple analytic account plans多辅助核算方案

    定义核算方案     菜单 会计/设置/辅助核算会计/多个方案         点击"创建"按钮         说明 辅助核算方案,输入方案名称     点击"添加一个 ...

  10. Struts2实现空表单信息的提示

    须要的jar包文件: index.jsp源代码: <%@ page language="java" contentType="text/html; charset= ...