# 「BZOJ3697」「FJ2014集训」采药人的路径

## 3697: 采药人的路径

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1723  Solved: 603
[Submit][Status][Discuss]

7
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1

1

## HINT

0和1用于区分路径上是否存在前缀和为i的节点。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int oo = 1e7;
const int N = 1e5 + 5;
int n,head[N],tov[2 * N],nex[2 * N],val[2 * N],sum;
int tot,size[N],root,mxdeep,MX,deep[N],dis[N],t[N];
ll f[2 * N][2],g[2 * N][2],ans;
bool vis[2 * N];

void add(int u,int v,int w) {

tot ++;
tov[tot] = v;
val[tot] = w;
}

void find_root(int u,int fa) {

size[u] = 1;
for(int i = head[u];i;i = nex[i]) {
int v = tov[i];
if(v == fa || vis[v]) continue;
find_root(v,u);
size[u] += size[v];
}
int cmp = max(sum - size[u],size[u]);
if(cmp < MX) {
MX = cmp;
root = u;
}
}

void dfs(int u,int fa,int dd) {

mxdeep = max(deep[u],mxdeep);
dis[u] = dd;
if(t[dis[u]]) f[dis[u]][1] ++;
else f[dis[u]][0] ++;
t[dis[u]] ++;
for(int i = head[u];i;i = nex[i]) {
int v = tov[i];
if(vis[v] || v == fa) continue;
deep[v] = deep[u] + 1;
dfs(v,u,dd + val[i]);
}
t[dis[u]] -- ;
}

void divide(int u) {

vis[u] = true; g[n][0] = 1;
deep[u] = 0; int mx = 0;
for(int i = head[u];i;i = nex[i]) {
int v = tov[i];
if(vis[v]) continue;
deep[v] = 1;
mxdeep = 1;
dfs(v,u,n + val[i]);
mx = max(mx,mxdeep);
ans += (g[n][0] - 1) * f[n][0];
for(int j = -mxdeep;j <= mxdeep;j ++) {
ans += g[n - j][1] * f[n + j][0] + g[n - j][0] * f[n + j][1] + g[n - j][1] * f[n + j][1];
}
for(int j = -mxdeep;j <= mxdeep;j ++) {
g[n - j][0] += f[n - j][0];
g[n - j][1] += f[n - j][1];
f[n - j][0] = f[n - j][1] = 0;
}
}
for(int j = -mx;j <= mx;j ++) {
g[n - j][0] = g[n - j][1] = 0;
}
for(int i = head[u];i;i = nex[i]) {
int v = tov[i];
if(vis[v]) continue;
sum = size[v]; MX = oo;
find_root(v,u);
divide(root);
}
}

int main( ) {

scanf("%d",& n);
for(int i = 1;i < n;i ++) {
int u,v,w;
scanf("%d%d%d",& u,& v,& w);
if(! w) w = -1;
}