BZOJ3697 采药人的路径

点分治。。。尼玛啊!蒟蒻怎么做的那么桑心%>_<%

Orz hzwer

蒟蒻就补充一下hzwer没讲的东西:

(1)对于阴性的植物权值设为-1,阳性的设为+1

(2)最后一段就是讲如何利用新的子树的f[]值求出ans和更新g[]

  1 /**************************************************************
  2     Problem: 3697
  3     User: rausen
  4     Language: C++
  5     Result: Accepted
  6     Time:1752 ms
  7     Memory:15924 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <algorithm>
 12
 13 using namespace std;
 14 const int N = 100005;
 15
 16 struct edge {
 17     int next, to, v;
 18     edge() {}
 19     edge(int _n, int _t, int _v) : next(_n), to(_t), v(_v) {}
 20 } e[N << 1];
 21
 22 int first[N], tot;
 23
 24 struct tree_node {
 25     int sz, dep, dis;
 26     bool vis;
 27 } tr[N];
 28
 29 int n, k;
 30 int cnt[N << 1];
 31 long long f[N << 1][2], g[N << 1][2], ans;
 32 int Root, Maxsz;
 33 int mx_dep, mx;
 34
 35 inline int read() {
 36     int x = 0;
 37     char ch = getchar();
 38     while (ch < ‘0‘ || ‘9‘ < ch)
 39         ch = getchar();
 40     while (‘0‘ <= ch && ch <= ‘9‘) {
 41         x = x * 10 + ch - ‘0‘;
 42         ch = getchar();
 43     }
 44     return x;
 45 }
 46
 47 void Add_Edges(int x, int y, int z) {
 48     e[++tot] = edge(first[x], y, z), first[x] = tot;
 49     e[++tot] = edge(first[y], x, z), first[y] = tot;
 50 }
 51
 52 void dfs(int p, int fa, int sz) {
 53     int x, y, maxsz = 0;
 54     tr[p].sz = 1;
 55     for (x = first[p]; x; x = e[x].next)
 56         if ((y = e[x].to) != fa && !tr[y].vis) {
 57             dfs(y, p, sz);
 58             tr[p].sz += tr[y].sz;
 59             maxsz = max(maxsz, tr[y].sz);
 60         }
 61     maxsz = max(maxsz, sz - tr[p].sz);
 62     if (maxsz < Maxsz)
 63         Root = p, Maxsz = maxsz;
 64 }
 65
 66 int get_root(int p, int sz) {
 67     Maxsz = N << 1;
 68     dfs(p, 0, sz);
 69     return Root;
 70 }
 71
 72 void Dfs(int p, int fa) {
 73     int x, y;
 74     mx_dep = max(mx_dep, tr[p].dep);
 75     if (cnt[tr[p].dis]) ++f[tr[p].dis][1];
 76     else ++f[tr[p].dis][0];
 77     ++cnt[tr[p].dis];
 78     for (x = first[p]; x; x = e[x].next)
 79         if ((y = e[x].to) != fa && !tr[y].vis) {
 80             tr[y].dep = tr[p].dep + 1, tr[y].dis = tr[p].dis + e[x].v;
 81             Dfs(y, p);
 82         }
 83     --cnt[tr[p].dis];
 84 }
 85
 86 void cal(int p) {
 87     int x, y, j;
 88     mx = 0, g[n][0] = 1;
 89     for (x = first[p]; x; x = e[x].next)
 90         if (!tr[y = e[x].to].vis) {
 91             tr[y].dis = n + e[x].v, tr[y].dep = 1, mx_dep = 1;
 92             Dfs(y, p);
 93             mx = max(mx, mx_dep);
 94             ans += (g[n][0] - 1) * f[n][0];
 95             for (j = -mx_dep; j <= mx_dep; ++j)
 96                 ans += g[n - j][1] * f[n + j][1] + g[n - j][0] * f[n + j][1] + g[n - j][1] * f[n + j][0];
 97             for (j = n - mx_dep; j <= n + mx_dep; ++j) {
 98                 g[j][0] += f[j][0], g[j][1] += f[j][1];
 99                 f[j][0] = f[j][1] = 0;
100             }
101         }
102     for (j = n - mx; j <= n + mx; ++j)
103         g[j][0] = g[j][1] = 0;
104 }
105
106 void work(int p, int sz) {
107     int root = get_root(p, sz), x, y;
108     tr[root].vis = 1;
109     cal(root);
110     for (x = first[root]; x; x = e[x].next)
111         if (!tr[y = e[x].to].vis)
112             work(y, tr[y].sz);
113 }
114
115 int main() {
116     int i, x, y, z;
117     n = read();
118     for (i = 1; i < n; ++i) {
119         x = read(), y = read(), z = read();
120         Add_Edges(x, y, z ? 1 : -1);
121     }
122     work(1, n);
123     printf("%lld\n", ans);
124     return 0;
125 }

(其实我觉得吧。。。点分治做到1600ms是极限了,rank最前面的两位应该用了特殊的技♂巧)

时间: 2024-12-21 17:49:02

BZOJ3697 采药人的路径的相关文章

BZOJ3697 采药人的路径 【点分治】

题目 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径.采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的.他想知道他一共可以选择多少种不同的路径. 输入格式 第1行包含一个整数N.

【BZOJ3697】采药人的路径 点分治

[BZOJ3697]采药人的路径 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径.采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的.他想知道他一共可以选择多少种

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

3697: 采药人的路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 681  Solved: 246[Submit][Status][Discuss] Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径.

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

点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. 然而这实在是太傻逼了,黄学长教做人:从父亲来更新儿子,走到一个节点直接更新路径的统计数,反正我们要的是[经过root的xx路径的数量] 所以可以一遍dfs直接搞出来…… 2.统计方案的方式也想错了……我只考虑了以root作为中转站的路径,然而经过root的路径中,并不只有这种路径是合法的……中转站在

P4930「FJ2014集训」采药人的路径

题目:P4930「FJ2014集训」采药人的路径 思路: 这篇不算题解,是让自己复习的,什么都没说清楚. 很久没有写点分治了,以前为了赶课件学的太急,板子都没打对就照着题解写题,导致学得很不扎实. 这道题差不多是在郭老师的指导下一点点凑出来的,还是没能自己完整写出一道题,惭愧. 这道题大意是:给出一棵边权为0/1的树,求满足以下条件的路径总数:0的个数等于1的个数,且路径上存在一点到路径两端也满足该条件. 这种求路径总数的题,可以想到用点分治. 把0看作-1,就可以转化为路径边权和为0. 如果没

【bzoj3697】采药人的路径 树的点分治

题目描述 给出一棵 $n$ 个点的树,每条边的边权为1或0.求有多少点对 $(i,j)$ ,使得:$i$ 到 $j$ 的简单路径上存在点 $k$ (异于 $i$ 和 $j$ ),使得 $i$ 到 $k$ 的简单路径上0和1数目相等,$j$ 到 $k$ 的简单路径上0和1数目也相等. 输入 第1行包含一个整数N.接下来N-1行,每行包含三个整数a_i.b_i和t_i,表示这条路上药材的类型. 输出 输出符合采药人要求的路径数目. 样例输入 71 2 03 1 12 4 05 2 06 3 15 7

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

Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径.采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的.他想知道他一共可以选择多少种不同的路径. Input 第1

【BZOJ 3697】采药人的路径

题目链接: TP 题解: 调了好久233. 大概想一想就是树分,然后考虑这样路径(u,v)的特征,以根节点(root)切开,u到root的阴阳差值,和v到root巧合互为相反数,然后考虑要有一个点可作为休息点,即u/v到root的路径中要有一点x与u/v到root的阴阳差值相同,然后维护一下就好. 注意的是阴阳差为0的特判……写挂了调好久,对拍也不好写,真是恶心. 代码: 1 #define Troy 11/23 2 #define inf 0x7fffffff 3 4 #include <bi

树的点分治讲解

在说点分治之前先说一下序列分治,序列分治大家都知道吧,就是把序列从某个位置(一般是中间点)分成两部分,统计跨越两部分的答案再递归处理两部分.树的点分治的道理和序列分治很像,但树没有中点,该怎么分治呢?再对比序列分治,序列相当于一条链,而序列的中点就是这条链的重心,那么树的分治点就可以是这棵树的重心.回顾一下重心的性质:以树的重心为根,这棵树最大子树大小不大于整棵树大小的一半.这样就可以保证时间复杂度是O(nlogn)(因为最多logn层啊qwq). 当以一个点为当前重心时,处理的答案是跨区域的(