3697: 采药人的路径

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1718  Solved: 602
[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

Sample Output

1

HINT

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

Source

 

[Submit][Status][Discuss]

HOME Back

点分治经典题。但是细节好多aaa!!

在计算$u$的贡献,即经过$u$的路径方案数时,记录两个数组,$f[dis][0/1]$和$g[dis][0/1]$,$f$表示这棵子树之前所有计算过的子树所作出的贡献。$g$表示当前计算的子树作出的贡献,在$dfs$中更新$g$,用完过后清零更新$f$。$0/1$表示这条到重心的路径上是否有休息站。在$dfs$中开一个桶,记录之前经过过的路径长度。每次回溯回去的时候释放桶。如果当前的$dis$之前就被装进桶中过,就表示从那时到现在的这条路径的$dis$为0,表示这条路径上肯定有一个休息站,更新$g[dis][1]$,否则更新$g[dis][0]$。

$ans$会从所有$f[i][0]*g[-i][1]+f[i][1]*g[-i][0]+f[i][1]*g[-i][1]$转移过来,表示至少有一个休息站和两个休息站的情况。注意,总的还要加上$g[0][0]*(f[0][0]-1)$,表示当前重心为休息站时的贡献,【注意】$f$减一是必须的,因为之前所有子树中计算的$dis$为0的路径还包括了当前重心这一个点,不能计算进去。而要计算从这个点延伸出去的合法链则一定会在后面的$f[0][0]*g[dis][1]$中被计算到,因为这条链如果满足条件,在这条链中的某一个点一定是休息站。

【注意】答案要存为long long

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std; const int N = ; int n; int stot, tov[N*], nex[N*], h[N], w[N*];
void add ( int u, int v, int s ) {
tov[++stot] = v;
w[stot] = s;
nex[stot] = h[u];
h[u] = stot;
} int siz[N], vis[N], size, asize, root;
void findroot ( int u, int f ) {
siz[u] = ;
int res = ;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( vis[v] || v == f ) continue;
findroot ( v, u );
siz[u] += siz[v];
res = max ( res, siz[v] );
}
res = max ( res, size - siz[u] );
if ( res < asize ) {
asize = res; root = u;
}
} ll g[N][], f[N][];
int t[N], dis[N], maxdep, dep[N];
void dfs ( int u, int f ) {
maxdep = max ( dep[u], maxdep );
if ( t[dis[u]] ) g[dis[u]][] ++;
else g[dis[u]][] ++;
t[dis[u]] ++;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( v == f || vis[v] ) continue;
dep[v] = dep[u] + ;
dis[v] = dis[u] + w[i];
dfs ( v, u );
}
t[dis[u]] --;
} ll ans;
void work ( int u ) {
vis[u] = ; int mx = ; f[n][] = ;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( vis[v] ) continue;
dis[v] = n + w[i]; dep[v] = ;
maxdep = ; dfs ( v, ); mx = max ( mx, maxdep );
ans += 1ll * ( f[n][] - ) * g[n][];
for ( int j = -maxdep; j <= maxdep; j ++ )
ans += f[n+j][] * g[n-j][] + f[n+j][] * g[n-j][] + f[n+j][] * g[n-j][];
for ( int j = -maxdep; j <= maxdep; j ++ ) {
f[n-j][] += g[n-j][]; g[n-j][] = ;
f[n-j][] += g[n-j][]; g[n-j][] = ;
}
}
for ( int i = -mx; i <= mx; i ++ )
f[n+i][] = f[n+i][] = ;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( !vis[v] ) {
asize = 0x3f3f3f3f, size = siz[v]; root = ;
findroot ( v, );
work ( root );
}
}
} int main ( ) {
scanf ( "%d", &n );
for ( int i = ; i < n; i ++ ) {
int u, v, s;
scanf ( "%d%d%d", &u, &v, &s );
s = s ? : -;
add ( u, v, s );
add ( v, u, s );
}
size = n; asize = 0x3f3f3f3f;
findroot ( , );
work ( root );
printf ( "%lld", ans );
return ;
}

【BZOJ】3697: 采药人的路径的更多相关文章

  1. [BZOJ 3697] 采药人的路径

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=3697 [算法] 首先 , 将黑色的边变成1 ,白色的边变成-1 那么 , 问题就转化 ...

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

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

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

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

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

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

  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. 1、编写第一个java程序--Hello—World

    1.下载JDK8.0文件 下载网址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.ht ...

  2. [整理] magento搬家

    将原来网站文件中的var文件中的cache和session文件删除,将media中的缓存文件删除.然后将所有文件制作成一个压缩包,以减少文件体积,方便转移. 将压缩包转移到新的服务器域名指向的文件夹, ...

  3. Ice Cream Tower Gym - 101194D (贪心 + 二分 )

    题目链接 : https://cn.vjudge.net/problem/Gym-101194D 题目大意 : 给你n个冰激凌球,让你用这些冰激凌球去垒冰激凌,要求是下面的这一个必须是他上面一个的两倍 ...

  4. 在Oracle中查询表的大小

    SELECT segment_name AS TABLENAME,round(BYTES/1024/1024,2)  FROM user_segments WHERE segment_name='表名 ...

  5. 我的Apache又挂了之apache错误:server's fully qualified domain name, using 127.0.0.1. Set the 'ServerName'

    表示物理机装Apache然后有时候关机会忘了关闭Apache然后长此以往会导致各种Apache起不来的缘故,上一次已经出现过一次.今天又出现了 再次记录一下解决的方法. 1.查看错误日志 /var/l ...

  6. 69.Spartan-6的SelectIO资源

    2.1.6 SelectIO资源 Spartan-6有丰富的I/O资源,包括SelectIO和RocketIO. Spartan-6每个I/O片(Tile)包含两个IOB.两个ILOGIC2.两个OL ...

  7. netif_receive_skb->__netif_receive_skb_core

    在设备驱动收包之后,会通过netif_receive_skb将收取的包,按照注册的协议回调,传递到上层进行处理: /* 将skb传递到上层 */ static int __netif_receive_ ...

  8. PC端网站跳转手机端网站

    <SCRIPT LANGUAGE="JavaScript"> function mobile_device_detect(url) { var thisOS=navig ...

  9. 791. Custom Sort String

    S and T are strings composed of lowercase letters. In S, no letter occurs more than once. S was sort ...

  10. html5本次存储几种方式

    一.cookies 大家都懂的,不必多说 二.sessionStorage/localStorage HTML5 LocalStorage 本地存储 说到本地存储,这玩意真是历尽千辛万苦才走到HTML ...