[bzoj3697]采药人的路径_点分治
采药人的路径 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]采药人的路径_点分治的更多相关文章
- BZOJ_3697_采药人的路径_点分治
BZOJ_3697_采药人的路径_点分治 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性 ...
- BZOJ3697 采药人的路径 【点分治】
题目 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径 ...
- BZOJ3697: 采药人的路径(点分治)
Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动 ...
- 2019.01.09 bzoj3697: 采药人的路径(点分治)
传送门 点分治好题. 题意:给出一棵树,边分两种,求满足由两条两种边数相等的路径拼成的路径数. 思路: 考虑将边的种类转化成边权−1-1−1和111,这样就只用考虑由两条权值为000的路径拼成的路径数 ...
- 【BZOJ-3697&3127】采药人的路径&YinandYang 点分治 + 乱搞
3697: 采药人的路径 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 681 Solved: 246[Submit][Status][Discus ...
- bzoj千题计划248:bzoj3697: 采药人的路径
http://www.lydsy.com/JudgeOnline/problem.php?id=3697 点分治 路径0改为路径-1 g[i][0/1] 和 f[i][0/1]分别表示当前子树 和 已 ...
- 【BZOJ3697】采药人的路径(点分治)
题意:采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径是很 ...
- BZOJ3697采药人的路径——点分治
题目描述 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径 ...
- BZOJ3697:采药人的路径(点分治)
Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药 ...
随机推荐
- 洛谷P1613 跑路(最短路+倍增)
P1613 跑路 题目描述 小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零.可是小A偏偏又有赖床的坏毛病.于是为了保住自己的工资,小A买了一个十分牛B的 ...
- Java常用集合类
上述类图中,实线边框的是实现类,比如ArrayList,LinkedList,HashMap等,折线边框的是抽象类,比如AbstractCollection,AbstractList,Abstract ...
- 【Codeforces1117C_CF1117C】Magic Ship(构造)
题目: Codeforces1117C 考的时候很困,开局半小时后才过A,只做出来AB,排名3000+,掉了119--半夜体验极差. 翻译: 你是一个船长.最初你在点 \((x_1,y_1)\) (显 ...
- NHibernate系列学习(一)-看看用NH怎么做增速改查
1.本次所有代码是在一下环境下运行的 学习系统:win8 64bit 开发环境:VS2013,MSSQL2012 NHibernate版本:NHibernate-4.0.3.GA [文章结尾有本次笔记 ...
- Android 使用WebView浏览有声音或者视频的网页,关闭WebView之后,声音或者视频不停止的解决办法
笔者最近使用Eclipse开发Android移动应用app,其实有一个功能是使用Android系统自带的WebView控件加载Web页面.开发很顺利,浏览也很正常.不过有个比较特殊的一点就是加载的We ...
- JS高级——变量提升
JS执行过程 1.首先是预解析:预解析过程最重要的是提升,在JavaScript代码在预解析阶段,会对以var声明的变量名,和function开头的语句块,进行提升操作 2.执行操作 全局中解析和执行 ...
- html5——动画案例(太阳系)
太阳系主要利用定位,伪元素 <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...
- Lazarus Reading XML- with TXMLDocument and TDOMNode
这里读取'HistoryPath' ,'TracePath' 元素下的‘value’属性使用的是 var xmlCfg: TXMLDocument; .... function ReadXMLCFG: ...
- HDU_1698_Just a Hook_线段树区间更新
Just a Hook Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- C# 计算百分比
//计算比率 decimal A =(decimal) 200.20; decimal B = (decimal)1000.20; decimal t = decimal.Parse((A/B).To ...