[题目链接]

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. 数据结构之区间K大数

    求区间的问题有很多类,虽然前人有很多讲解了: 但是我在这里在普及一下,算是自己的一种复习吧. 1.静态询问一个区间的的第k大数,比如询问[l,r] k大数.虽然主席树可以处理,但是这类问题应该是划分树 ...

  2. NOIP前必须记住的30句话

    NOIP前必须记住的30句话 1.比赛前一天晚上请准备好你的各种证件,事先查好去往考场的路线2.比赛之前请先调整你的屏幕分辨率到你喜欢的大小3.比赛之前请把编译器的字体调为你平时惯用的字体,尤其是注意 ...

  3. memcached安装与初步

    mac 首先安装homebrew 根目录下 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew ...

  4. Spring的IoC容器概述

    以下内容引用自http://wiki.jikexueyuan.com/project/spring/ioc-containers.html: IoC容器 Spring容器是Spring框架的核心.容器 ...

  5. Go -- 今日头条架构

    夏绪宏,今日头条架构师,专注对高性能大规模 Web 架构,云计算.性能优化.编程语言理论等方向,PHP committer,HHVM 项目贡献者.2009 加入百度,先后从事大规模 IDC 自运维设施 ...

  6. DataGuard备库ORA-01196故障恢复一则

    问题现象 在使用shutdown abort停DataGuard备库后.备库不能open,报ORA-01196错误. 详细例如以下: 发现一备库不能应用日志.查看备库日志没发现报错.怀疑是备库应用日志 ...

  7. 线程池实例:使用Executors和ThreadPoolExecutor

    线程池负责管理工作线程,包含一个等待执行的任务队列.线程池的任务队列是一个Runnable集合,工作线程负责从任务队列中取出并执行Runnable对象. java.util.concurrent.ex ...

  8. c#中的多态 c#中的委托

    C#中的多态性          相信大家都对面向对象的三个特征封装.继承.多态很熟悉,每个人都能说上一两句,但是大多数都仅仅是知道这些是什么,不知道CLR内部是如何实现的,所以本篇文章主要说说多态性 ...

  9. 给大二学生——能够再坚持一年的ACM

    [来信] 我是大二学生,就读于一所非常普通的大学.学校ACM基本零起步,去年才開始搞,我大一大二花了非常多时间搞acm,如今不太想放弃.但学校基本没人愿意搞这个. 非常快就要大三了,我一直在纠结要不要 ...

  10. sanic官方文档解析之Example(一)

    1,示例 这部的文档是简单的示例集合,它能够帮助你快速的启动应用大部分的应用,这些应用大多事分类的,并且提供给ini工作的连接代码: 1.1,基础示例 这部分示例集成了提供简单sanic简单的代码 单 ...