题目大意:

从前有一棵无向树,树上边权均为$0$或$1$,有一个采药人,他认为如果一条路径上边权为$0$和$1$的边数量相等,那么这条路径阴阳平衡。他想寻找一条合法的采药路径,保证阴阳平衡。然后他发现采药很累,于是乎他需要保证这条路径上有一个中转站,路径两个端点到中转站的路径都需要阴阳平衡 $n \leqslant 10^{5}$,求合法路径数

把$0$边边权变成$-1$,易发现如果一条路径阴阳平衡,那么边权总和为$0$

由于是树上路径的计数问题,考虑树分治,每次选中心作为根,设某点$x$到根的路径的边权和为$dis_{x}$

把中转站加进去会发生什么呢?

如果某个点$x$到根的路径上能设置中转站,那么根到$x$的路径上一定存在一点$y$,$dis_{y}=dis_{x}$,即$x$到$y$的路径$dis$为$0$,这个操作可以用桶实现

现在要在根统计答案了,显然每个点分为种情况,到根的路径能设置中转站和不能,用桶分别计数即可,设为$f[i][0]$和$f[i][1]$,表示$dis=i$时的方案数

发现还有$dis<0$的情况,需要额外记录一个数组$g$

那么答案就是$\sum_{i=1} f[i][0]*g[i][1]+f[i][1]*g[i][0]+f[i][1]*g[i][1]$

还要去掉不合法的情况,在当前根的每个子节点依然进行上述方法计数即可

$dis=0$的情况需要单独讨论,所有$dis=0$的路径都能两两匹配。此外,不以根节点为中转站,且$dis=0$的路径也一定合法

细节比较多

 #include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 100010
#define M1 (N1<<1)
#define ll long long
#define inf 233333333
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int n; struct Edge{
int to[M1],nxt[M1],val[M1],head[N1],cte;
void ae(int u,int v,int w)
{cte++;to[cte]=v,nxt[cte]=head[u],val[cte]=w,head[u]=cte;}
}E; int use[N1],mi,G,S,tsz,ma;
int sf[N1],sg[N1],ms[N1],sz[N1],dis[N1];
int f[N1][],g[N1][]; ll ans; int que[N1],tl;
//int dep[N1],fa[N1],de;
void dfs_sum(int u,int dad)
{
que[++tl]=u;
if(dis[u]>=){
if(sf[dis[u]]) f[dis[u]][]++;
else f[dis[u]][]++;
sf[dis[u]]++; ma=max(ma,dis[u]);
if(u==S) sf[]--,f[][]--;
}else{
if(sg[-dis[u]]) g[-dis[u]][]++;
else g[-dis[u]][]++;
sg[-dis[u]]++; ma=max(ma,-dis[u]);
}
for(int j=E.head[u];j;j=E.nxt[j])
{
if(E.to[j]==dad||use[E.to[j]]) continue;
dis[E.to[j]]=dis[u]+E.val[j];
dfs_sum(E.to[j],u);
}
if(dis[u]>=) sf[dis[u]]--;
else sg[-dis[u]]--;
}
void gra(int u,int dad)
{
sz[u]=; ms[u]=;
for(int j=E.head[u];j;j=E.nxt[j])
{
int v=E.to[j];
if(v==dad||use[v]) continue;
gra(v,u); sz[u]+=sz[v];
ms[u]=max(ms[u],sz[v]);
}
ms[u]=max(ms[u],tsz-sz[u]);
if(ms[u]<ms[G]) G=u;
}
void clr()
{
int x;
while(tl)
{
x=que[tl]; tl--;
if(dis[x]>=) f[dis[x]][]=f[dis[x]][]=;
else g[-dis[x]][]=g[-dis[x]][]=;
}
sg[]=sf[]=;
}
void calc(int u,int type)
{
ma=; dfs_sum(u,-);
ans+=( 1ll*f[][]*(f[][]-)/ + 1ll*f[][]*(f[][]-)/ + 1ll*f[][]*f[][] )*type;
for(int i=;i<=ma;i++)
ans+=( 1ll*f[i][]*g[i][] + 1ll*f[i][]*g[i][] + 1ll*f[i][]*g[i][])*type;
if(type==) ans+=f[][];
clr();
}
void main_dfs(int u)
{
int j,v; use[u]=; S=u; dis[u]=; calc(u,);
for(j=E.head[u];j;j=E.nxt[j])
{
v=E.to[j]; if(use[v]) continue;
G=; tsz=sz[v]; gra(v,u);
calc(v,-);
main_dfs(G);
}
} int main()
{
//freopen("t2.in","r",stdin);
int i,x,y,z;
scanf("%d",&n);
for(i=;i<n;i++)
{
x=gint(),y=gint(),z=gint();
z=((z)?:-);
E.ae(x,y,z),E.ae(y,x,z);
}
ms[]=tsz=n; G=; gra(,-); gra(G,-);
main_dfs(G);
printf("%lld\n",ans);
return ;
}

BZOJ 3697/3127 采药人的路径 (点分治)的更多相关文章

  1. 【BZOJ 3697】采药人的路径

    题目链接: TP 题解: 调了好久233. 大概想一想就是树分,然后考虑这样路径(u,v)的特征,以根节点(root)切开,u到root的阴阳差值,和v到root巧合互为相反数,然后考虑要有一个点可作 ...

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

    点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. ...

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

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

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

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

  5. BZOJ 3697: 采药人的路径 点分治

    好久不做点分治的题了,正好在联赛之前抓紧复习一下. 先把边权为 $0$ 的置为 $-1$.定义几个状态:$f[dis][0/1],g[dis][0/1]$ 其中 $f$ 代表在当前遍历的子树内的答案. ...

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

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

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

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

  8. [bzoj3697]采药人的路径——点分治

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

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

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

随机推荐

  1. Linux操作随笔

    1.查看php加载的模块 /usr/local/php/bin/php -m |less 2.查询连接数 netstat -ntu | awk '{print $5}' | cut -d: -f1 | ...

  2. win主机ping不通linux的IP

    1.虚拟机的中的linux系统设置成桥接模式 2.点击虚拟机的编辑选择虚拟网络编辑器 3.点击更改设置 4点击还原默认设置即可

  3. MAVEN 的常用命令

    1.清除命令:mvn clean 2.编译命令:mvn  conpile 3.打包命令:mvn package 4.跳过单元测试命令:mvn clean package -Dmaven.test.sk ...

  4. 提高生产力:SpringMVC中,使用扩展数据类型TypedMap接收Web请求参数

    在Web项目中,如果前端MVC框架使用的是SpringMVC,可以使用Map接收前端请求参数,比bean要方便很多. 尤其是SpringMVC和Mybatis一起用的时候,用Map大大减少了需要的be ...

  5. 【hihocoder 1308】搜索二·骑士问题

    [题目链接]:http://hihocoder.com/problemset/problem/1308 [题意] [题解] 用bfs处理出3个骑士到每个点的最短路; 然后枚举最后3个骑士到了哪一个点. ...

  6. SSH框架整合截图总结(三)

    联系人信息查询1 点击 联系人信息查询 超链接时候,到查询页面 (1)在查询页面中,选择客户,根据客户进行查询 下拉表框显示所有客户  可以根据所属的客户进行联系人查询  2 在查询页面中,输入值,提 ...

  7. BZOJ 3674 可持久化并查集加强版(路径压缩版本)

    /* bzoj 3674: 可持久化并查集加强版 http://www.lydsy.com/JudgeOnline/problem.php?id=3674 用可持久化线段树维护可持久化数组从而实现可持 ...

  8. 图像算法研究---Adaboost算法具体解释

    本篇文章先介绍了提升放法和AdaBoost算法.已经了解的可以直接跳过.后面给出了AdaBoost算法的两个样例.附有详细计算过程. 1.提升方法(来源于统计学习方法) 提升方法是一种经常使用的统计学 ...

  9. Java——动态代理

    在静态代理中,我们在调用target类的时候,都是先拿到proxy类.由于proxy类中将target类作为了成员变量,而且跟target类继承了一样的接口,具有同样的方法,所以,在proxy类中.通 ...

  10. 杭电1018-Big Number(大数)

    Big Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...