BZOJ 3697/3127 采药人的路径 (点分治)
题目大意:
从前有一棵无向树,树上边权均为$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 采药人的路径 (点分治)的更多相关文章
- 【BZOJ 3697】采药人的路径
题目链接: TP 题解: 调了好久233. 大概想一想就是树分,然后考虑这样路径(u,v)的特征,以根节点(root)切开,u到root的阴阳差值,和v到root巧合互为相反数,然后考虑要有一个点可作 ...
- 【BZOJ】【3697】采药人的路径&【3127】【USACO2013 Open】Yin and Yang
点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. ...
- 【BZOJ3697】采药人的路径 点分治
[BZOJ3697]采药人的路径 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是 ...
- BZOJ 3697: 采药人的路径 [点分治] [我想上化学课]
传送门 题意: 路径有$-1,1$两种权值,求有多少路径满足权值和为$0$且有一个点将路径分成权值和为$0$的两段 第四节课本来想去上化学,然后快上课了这道题还没调出来.....可恶我想上化学 昨天两 ...
- BZOJ 3697: 采药人的路径 点分治
好久不做点分治的题了,正好在联赛之前抓紧复习一下. 先把边权为 $0$ 的置为 $-1$.定义几个状态:$f[dis][0/1],g[dis][0/1]$ 其中 $f$ 代表在当前遍历的子树内的答案. ...
- BZOJ3697采药人的路径——点分治
题目描述 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径 ...
- BZOJ3697:采药人的路径(点分治)
Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药 ...
- [bzoj3697]采药人的路径——点分治
Brief Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天 ...
- 【BZOJ-3697&3127】采药人的路径&YinandYang 点分治 + 乱搞
3697: 采药人的路径 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 681 Solved: 246[Submit][Status][Discus ...
随机推荐
- 纯css3实现箭头、关闭按钮旋转效果
说起css3的旋转效果,那就要说为什么不用js去实现,CSS3的动画效果,能够减少对JavaScript和Flash文件的HTTP请求这是原因之一.但是css3可能要求浏览器执行很多的工作来完成这个动 ...
- 【模板】 最大流模板(ISAP)
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- Hibernate Session操作
1.增加 @Test public void add(){ Configuration cfg=new Configuration().configure(); SessionFactory fact ...
- Linux安装expect命令
[Linux安装expect命令]:--expect是在Tcl基础上创建起来的,所以在安装expect前我们应该先安装Tcl.①:tcl安装源码下载:http://www.tcl.tk/softwar ...
- 我的第一个arcgis地图应用
步骤: 1.设置一个基本的html文档 <!DOCTYPE html> <html> <head> <meta http-equiv="Conten ...
- 用chrony代替ntpd时间同步服务器
Chrony是一个开源的自由软件,它能保持系统时钟与时钟服务器(NTP)同步,让时间保持精确. 它由两个程序组成:chronyd和chronyc. chronyd是一个后台运行的守护进程,用于调整内核 ...
- Appium遇到问题:
问题一:问题org.openqa.selenium.remote.UnreachableBrowserException: Could not start a new session. Possibl ...
- (7)JPA - Hibernate【从零开始学Spring Boot】
在说具体如何在spring boot 使用Hibernate前,先抛装引玉些知识点?什么是JPA呢? JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象- ...
- CF409C Magnum Opus
CF409C Magnum Opus 题意翻译 题目背景 愚人节题目,题面似乎是一位名叫Nicolas Flamel的炼金术士用拉丁文写的某种物质的配方,结合谷歌尝试翻译了一下: 吾友: 哲人石所言不 ...
- HDU 2521
了解反素数的定义: 反素数是指[1,n]内,比n小的数的约数个数都比n的约数个数要少.注意n其实是最后一个.而在区间内,[a,b]是明显无法满足条件的. 注意了最大才5000.所以,不妨使用枚举. # ...