BZOJ 3697 采药人的路径 点分治
2016-04-05 23:51
369 查看
由于不知道两种颜色的和,但是如果将两种颜色分别设为1和-1,那么符合条件的和必为0,以这个树分治即可。
数组必须可以索引负值为了不调试使代码长了好多。。
采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。
接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。
数组必须可以索引负值为了不调试使代码长了好多。。
#include <queue> #include <cstdio> #include <algorithm> const int N = 100005, M = N * 2; using namespace std; struct SimpleArray { int c[2]; int &operator [](int x) { return c[x]; } }; template<class T> struct Array { T c[N * 2]; T &operator [](int x) { return c[N + x]; } }; int vis[M], p[M], v[M], h , w[M], cnt = 1, node, rt; long long ans = 0; int d , sz ; Array<SimpleArray> f, g; Array<int> s; void add(int a, int b, int c) { p[++cnt] = h[a]; v[cnt] = b; w[cnt] = c; h[a] = cnt; } void root(int x, int fa) { sz[x] = 1; d[x] = 0; for (int i = h[x]; i; i = p[i]) if (v[i] != fa && !vis[i]) { root(v[i], x); sz[x] += sz[v[i]]; d[x] = max(d[x], sz[v[i]]); } d[x] = max(d[x], node - sz[x]); if (d[x] < d[rt]) rt = x; } int get_root(int x, int fa, int sz) { rt = 0; node = sz; d[0] = 2147483647; root(x, fa); return rt; } void dfs_seq(int x, int fa, int dep, int dis, int &mxdep) { mxdep = max(mxdep, dep); ++g[dis][s[dis] ? 1 : 0]; ++s[dis]; for (int i = h[x]; i; i = p[i]) if (!vis[i] && v[i] != fa) dfs_seq(v[i], x, dep + 1, dis + w[i], mxdep); --s[dis]; } void work(int x) { int i, j, mxdep, mx = 0; f[0][0] = 1; for (i = h[x]; i; i = p[i]) if (!vis[i]) { mxdep = 1; dfs_seq(v[i], x, 1, w[i], mxdep); mx = max(mx, mxdep); ans += g[0][0] * (f[0][0] - 1); for (j = -mxdep; j <= mxdep; ++j) ans += g[j][0] * f[-j][1] + g[j][1] * f[-j][0] + g[j][1] * f[-j][1]; for (j = -mxdep; j <= mxdep; ++j) { f[j][0] += g[j][0]; f[j][1] += g[j][1]; g[j][0] = g[j][1] = 0; } } for (j = -mx; j <= mx; ++j) f[j][0] = f[j][1] = 0; for (i = h[x]; i; i = p[i]) if (!vis[i]) { vis[i] = vis[i ^ 1] = true; work(get_root(v[i], x, sz[v[i]])); } } int main() { int a, b, c, i, n; scanf("%d", &n); for (i = 1; i < n; ++i) { scanf("%d%d%d", &a, &b, &c); c = c ? 1 : -1; add(a, b, c); add(b, a, c); } work(get_root(1, 0, n)); printf("%lld", ans); return 0; }
3697: 采药人的路径
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。相关文章推荐
- PHP设计模式 享元设计模式
- OpenWrt LuCI 汉化指南
- 软件的可维护性与哪些因素有关?在软件开发过程中应该采取哪些措施来提高软件产品的可维护性?
- Java递归算法——三角数字
- django之创建第10-1个项目-图片上传并记录上传时间
- 破解android手机图形锁
- opencv for python学习二之打开视频文件
- mysql优化手段——潭州学院
- 应用内置embeded tomcat,并打包为fat jar的解决方案
- 递归(一)
- 相位变化对于真实信号的影响是什么?
- 图文混排 ——SpannableStringBuilder的使用
- Android测试之旅之JUnit(一)
- HDU 1210
- ListView结合PullToRefreshScrollView 下拉刷新
- HoloLens开发学习笔记(二):学习资源整理
- hdu-4417 Super Mario(树状数组 + 划分树)
- <activity>
- 常用软件使用记录
- 使用qwebpage来下载资源