采药人的路径 bzoj-3697

    题目大意:给你一个n个节点的树,每条边分为阴性和阳性,求满足条件的链的个数,使得这条链上阴性的边的条数等于阳性的边的条数,且这条链上存在一个节点,这个节点到一个端点的链也是阴阳相等,到另一个顶点也是阴阳相等。
    注释:$1\le n \le 10^5$。

      想法:点分治裸题,开始净想着怎么在一条阴阳相等的链上找点了。其实可以在找初步满足条件的链是就直接处理出完全满足条件者。首先,我们先令阳性为1,阴性为-1,求边权和为0即为阴阳相等。紧接着,我们定义

        f[i][1]表示root的子树中满足到重心的链且边权和为i、存在一个点使得该点到这条链上到不是重心的另一个节点的边权和为0的条数。

        f[i][0]同理,只是不存在这样的点。

        g[i][1/0]表示边权和为-i。

      特别地,因为所有的边权都是1 or -1,所以我可以在dfs链的时候直接判断出是否存在这样的节点。具体地:这条链的边权是x,如果这个节点相对于重心是根节点来讲存在一个祖先,使得这个祖先到根节点的边权和也是x,那么显然就存在这样的节点,就是那个祖先。然后,我们可以用l和r分别表示这个点之前祖先的边权和所能达到的下界和上界。因为边权是1 or -1,所以$[l,r]$之间的所有值都是可以取到的。这就处理出了f和g数组。

      剩下的,就是运用单步容斥和简单的点分治模板套用,注意size的问题(抄的GXZlegend的代码,所以就没特意更改size的错误)。

    最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
}#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
int head[N],to[N<<1],val[N<<1],next[N<<1],cnt,vis[N],si[N],ms[N],sum,root,md;
long long f[N][2],g[N][2],ans;
inline void add(int x,int y,int z)
{
to[++cnt]=y,val[cnt]=z,next[cnt]=head[x],head[x]=cnt;
}
void getroot(int x,int fa)
{
si[x]=1,ms[x]=0;
for(int i=head[x];i;i=next[i])
if(!vis[to[i]]&&to[i]!=fa)
getroot(to[i],x),si[x]+=si[to[i]],ms[x]=max(ms[x],si[to[i]]);
ms[x]=max(ms[x],sum-si[x]);
if(ms[x]<ms[root]) root=x;
}
void calc(int x,int fa,int now,int cnt)
{
if(now==0)
{
if(cnt>=2)ans++;
cnt++;
}
for(int i=head[x];i;i=next[i])
if(!vis[to[i]]&&to[i]!=fa)
calc(to[i],x,now+2*val[i]-1,cnt);
}
void dfs(int x,int fa,int now,int l,int r)
{
if(now>=l&&now<=r)
{
if(now>=0)f[now][1]++;
else g[-now][1]++;
}
else
{
if(now>=0)f[now][0]++;
else g[-now][0]++;
}
l=min(l,now),r=max(r,now),md=max(md,max(-l,r));
for(int i=head[x];i;i=next[i])
if(!vis[to[i]]&&to[i]!=fa)
dfs(to[i],x,now+val[i]*2-1,l,r);
}
void solve(int x)
{
vis[x]=1,md=0,calc(x,0,0,0);
dfs(x,0,0,1,-1),ans+=f[0][1]*(f[0][1]-1)/2,f[0][0]=f[0][1]=0;
for(int i=1;i<=md;i++)ans+=f[i][0]*g[i][1]+f[i][1]*g[i][0]+f[i][1]*g[i][1],f[i][0]=f[i][1]=g[i][0]=g[i][1]=0;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]])
{
md=0,dfs(to[i],0,2*val[i]-1,0,0),ans-=f[0][1]*(f[0][1]-1)/2,f[0][0]=f[0][1]=0;
for(int j=0;j<=md;j++)ans-=f[j][0]*g[j][1]+f[j][1]*g[j][0]+f[j][1]*g[j][1],f[j][0]=f[j][1]=g[j][0]=g[j][1]=0;
sum=si[to[i]],root=0,getroot(to[i],0),solve(root);
}
}
}
int main()
{
int n,x,y,z;
scanf("%d",&n);
for(int i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
sum=n;
root=0;
ms[0]=n;
getroot(1,0);
solve(root);
printf("%lld\n",ans);
return 0;
}

    小结:在更新l和r时now的值并没有进行更改,所以不需要特殊处理,也就是当前的calc的now是可以直接拿来用的。

[bzoj3697]采药人的路径_点分治的更多相关文章

  1. BZOJ_3697_采药人的路径_点分治

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

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

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

  3. BZOJ3697: 采药人的路径(点分治)

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

  4. 2019.01.09 bzoj3697: 采药人的路径(点分治)

    传送门 点分治好题. 题意:给出一棵树,边分两种,求满足由两条两种边数相等的路径拼成的路径数. 思路: 考虑将边的种类转化成边权−1-1−1和111,这样就只用考虑由两条权值为000的路径拼成的路径数 ...

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

    3697: 采药人的路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 681  Solved: 246[Submit][Status][Discus ...

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

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

  7. 【BZOJ3697】采药人的路径(点分治)

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

  8. BZOJ3697采药人的路径——点分治

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

  9. BZOJ3697:采药人的路径(点分治)

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

随机推荐

  1. cmd执行Java程序

    先创建一个文本,里面内容为 public class hello{ public static void main(String[] arg) { System.out.println("H ...

  2. git配置用户信息

    git配置用户信息 一.在本地配置用户信息 配置内容:user.name 和 user.email 配置目的:Git用来记录谁做了什么事 配置方法:windows下打开Git Bash进行操作  gi ...

  3. vue tab 点击请求方法

    页面: <Tabs value="name1" style="width: 100%;height: 900px;" @on-click="ge ...

  4. PHP电影小爬虫(2)

    学习了别人的爬虫后自己改的一个,算是又回顾了一下php的使用 我们来利用simple_html_dom的采集数据实例,这是一个PHP的库,上手很容易.simple_html_dom 可以很好的帮助我们 ...

  5. UNIX环境高级编程--2

    UNIX标准及实现 ISO C: 国际标准化组织(International Organization for standardization , ISO)ISO C标准的意图是提供C程序的可移植性, ...

  6. 如何用putty链接服务器端,并安装wdcp

    首先把自己阿里云的磁盘格式化然后重启 自己下载一个PuTTY 打开后输入自己的Ip地址端口号默认是22 会跳出一个yes 跟no界面,点击yes 会进入一个类似cmd界面 直接输入root,然后会提示 ...

  7. Hive扩展功能(八)--表的索引

    软件环境: linux系统: CentOS6.7 Hadoop版本: 2.6.5 zookeeper版本: 3.4.8 主机配置: 一共m1, m2, m3这三部机, 每部主机的用户名都为centos ...

  8. Object未定义

    js加载时会在jquery中报Object未定义的错误? 原因: 页面和iframe页面中都引入了jquery 或者 是页面中包含iframe,并且在iframe没有完成加载前操作了iframe中的j ...

  9. 文件下载之ServletOutputStream

    使用response.getOutputStream可以获取ServletOutputStream,从而实现向页面发送流数据.但是需要注意的是,不能使用ajax进行请求,因为这样页面不会有任何反应,可 ...

  10. opencv 图像各方向旋转

    1. 简介 计算机图形学中的应用非常广泛的变换是一种称为仿射变换的特殊变换,在仿射变换中的基本变换包括平移.旋转.缩放.剪切这几种.本文以及接下来的几篇文章重点介绍一下关于旋转的变换,包括二维旋转变换 ...