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

解题思路:

点分治要求在寻找到一条链时统计答案与重心在链的哪个位置无关。而显然这道题如果枚举重心为中转站是错误的,因为一条链只被统计一次,而中心位置很可能是错误的,所以我们需要修正这一点,就是统计重心路径上可能出现的中心位置。

换句话说,开四个桶来记录,分别记录当前子树内可能出现的中转站(出现过的距离重复,在差分的意义下说明出现和为0的区间),另外一个就是之前子树的答案,每次更新完合并桶就好了。

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 typedef long long lnt;
  5 const int N=100010;
  6 struct pnt{
  7     int hd;
  8     int dis;
  9     int wgt;
 10     bool vis;
 11 }p[N];
 12 struct ent{
 13     int twd;
 14     int lst;
 15     int vls;
 16 }e[N<<1];
 17 lnt f[N<<1][2],g[N<<1][2];
 18 int has[N<<1];
 19 int n;
 20 lnt top;
 21 int cnt;
 22 lnt ans;
 23 int lim;
 24 int size;
 25 int root;
 26 int maxsize;
 27 void ade(int f,int t,int v)
 28 {
 29     cnt++;
 30     e[cnt].twd=t;
 31     e[cnt].lst=p[f].hd;
 32     e[cnt].vls=v;
 33     p[f].hd=cnt;
 34     return ;
 35 }
 36 void grc_dfs(int x,int f)
 37 {
 38     p[x].wgt=1;
 39     int maxs=-1;
 40     for(int i=p[x].hd;i;i=e[i].lst)
 41     {
 42         int to=e[i].twd;
 43         if(to==f||p[to].vis)
 44             continue;
 45         grc_dfs(to,x);
 46         p[x].wgt+=p[to].wgt;
 47         if(p[to].wgt>maxs)
 48             maxs=p[to].wgt;
 49     }
 50     if(maxs<size-p[x].wgt)
 51         maxs=size-p[x].wgt;
 52     if(maxs<maxsize)
 53     {
 54         maxsize=maxs;
 55         root=x;
 56     }
 57     return ;
 58 }
 59 void ans_dfs(int x,int fa,int dep)
 60 {
 61     lim=std::max(lim,dep);
 62     if(has[p[x].dis])
 63         f[p[x].dis][1]++;
 64     else
 65         f[p[x].dis][0]++;
 66     has[p[x].dis]++;
 67     for(int i=p[x].hd;i;i=e[i].lst)
 68     {
 69         int to=e[i].twd;
 70         if(to==fa||p[to].vis)
 71             continue;
 72         p[to].dis=p[x].dis+e[i].vls;
 73         ans_dfs(to,x,dep+1);
 74     }
 75     has[p[x].dis]--;
 76     return ;
 77 }
 78 void bin_dfs(int x)
 79 {
 80     int maxd=0;
 81     p[x].vis=true;
 82     g[n][0]=1;
 83     for(int i=p[x].hd;i;i=e[i].lst)
 84     {
 85         int to=e[i].twd;
 86         if(p[to].vis)
 87             continue;
 88         p[to].dis=n+e[i].vls;
 89         lim=1;
 90         ans_dfs(to,to,1);
 91         maxd=std::max(maxd,lim);
 92         ans+=f[n][0]*(g[n][0]-1);
 93         for(int j=-lim;j<=lim;j++)
 94             ans+=g[n-j][1]*f[n+j][1]+g[n-j][1]*f[n+j][0]+g[n-j][0]*f[n+j][1];
 95         for(int j=n-lim;j<=n+lim;j++)
 96         {
 97             g[j][0]+=f[j][0];
 98             g[j][1]+=f[j][1];
 99             f[j][0]=f[j][1]=0;
100         }
101     }
102     for(int i=n-maxd;i<=n+maxd;i++)
103         g[i][0]=g[i][1]=0;
104     for(int i=p[x].hd;i;i=e[i].lst)
105     {
106         int to=e[i].twd;
107         if(p[to].vis)
108             continue;
109         root=0;
110         size=p[to].wgt;
111         maxsize=0x3f3f3f3f;
112         grc_dfs(to,to);
113         bin_dfs(root);
114     }
115     return ;
116 }
117 int main()
118 {
119     scanf("%d",&n);
120     for(int i=1;i<n;i++)
121     {
122         int a,b,c;
123         scanf("%d%d%d",&a,&b,&c);
124         c=c*2-1;
125         ade(a,b,c);
126         ade(b,a,c);
127     }
128     root=0;
129     size=n;
130     maxsize=0x3f3f3f3f;
131     grc_dfs(1,1);
132     bin_dfs(root);
133     printf("%lld\n",ans);
134     return 0;
135 }

转载于:https://www.cnblogs.com/blog-Dr-J/p/10159463.html

BZOJ3697: 采药人的路径(点分治)相关推荐

  1. bzoj千题计划248:bzoj3697: 采药人的路径

    http://www.lydsy.com/JudgeOnline/problem.php?id=3697 点分治 路径0改为路径-1 g[i][0/1] 和 f[i][0/1]分别表示当前子树 和 已 ...

  2. bzoj3697 采药人的路径

    Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药 ...

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

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

  4. bzoj3784 树上的路径 点分治+RMQ+优先队列

    题目分析 树上的路径路径?可以,这很点分治. 求最长的mmm条的长度?可以,着很优先队列. 但问题是,用优先队列只能做全局才能保证复杂度是对的,但点分治是分治就不能做全局. 于是对于每次点分治,都记录 ...

  5. 点分治问题 ----------- 2019西安邀请赛 j and and and[点分治]

    题目链接 解题思路: 首先我们知道直接算很麻烦,我们对每条xor和为0的路径进行单独考虑. 1.我们知道对于每条xor和为0的路径,它对答案的贡献是,除了这个路径方向的子树大小的乘积. 2.那么很明显 ...

  6. 【技巧总结】——关于不知道放到哪里的小技巧

    [技巧总结]--关于不知道放到哪里的小技巧 折半搜索 分治 0,1,-1转化 模型转换 [ExtendingSetofPointsExtending\;Set\;of\;PointsExtending ...

  7. 一句话题解(20180210~)

    2.9 BZOJ 2006 [NOI2010]超级钢琴.这道题目几天之前就做了.做法是固定右端点,左端点在ST表上走,走法其实就是笛卡尔树的走法.完结撒花! BZOJ 1218 [HNOI2003]激 ...

  8. 动态规划:经典题目汇总

    动态规划:经典题目汇总 文章目录 动态规划:经典题目汇总 一.动态规划的定义 二.经典例题 3.1 一维的DP:斐波那契数列.[使用最小花费爬楼梯](https://leetcode-cn.com/p ...

  9. YbtOJ#20078-[NOIP2020模拟赛B组Day7]路径之和【分治,Flody】

    正题 题目链接:http://noip.ybtoj.com.cn/contest/108/problem/4 题目大意 nnn个点,每次只封闭一个点,求剩下点对两两之间的最短路和. 解题思路 Flod ...

最新文章

  1. 使用组策略实现文件复制
  2. C#如何在钉钉开发平台中创建部门
  3. LeetCode 100.相同的树(C++)
  4. matlab自动排版,工具方法| Matlab 简单绘图与排版
  5. 看了三张照片,这个AI只用20分钟破获六年“悬案”
  6. devops工程师_DevOps工程师的认证
  7. 【U-Net】【粗读】U-Net: Convolutional Networks for Biomedical Image Segmentation
  8. HTML示例06---水平线
  9. sun cluster 3.3 +oracle 10g R2 RAC with ASM on solaris 10 U9
  10. win10系统优化小工具:Windows10系统优化辅助工具.bat(批处理)
  11. GYM 101173 K.Key Knocking(构造)
  12. 微信小程序 之wx.previewImage图片预览(多张图片预览)
  13. 读书印记 - 《文案创作完全手册:文案大师教你一步步写出销售力》
  14. Qt绘制旋转的轮播图
  15. 经验谈系列 我们应该怎么给父母配电脑
  16. 基于矩阵分解的协同过滤算法
  17. [强制类型转换]C语言中的强制类型转换相关
  18. Steam Apex Legends 最简单领取方法,不需要改地区
  19. 知乎-产品经理观后总结
  20. linux画平面图软件,Sweet Home 3D傻瓜平面图软件,人人都能画出室内平面图

热门文章

  1. 磁盘格式化,磁盘挂载,手动增加swap空间
  2. 免费指纹浏览器破解方法之开源代码
  3. GD项目回顾总结之预热
  4. gitweb的安装(四)
  5. import _winreg:用python操作修改windows注册表
  6. 从 Windows 切换到 Linux?看这篇就够了!
  7. java ReentrantLock 实现原理
  8. 完整的一次 HTTP 请求响应过程(一)
  9. 25.C++:最通俗的讲解,什么是面向过程?什么是面向对象?
  10. element ui 前台模板_用 Vue+ElementUI 搭建后台管理极简模板