【BZOJ 3697】采药人的路径

题目链接:

  TP

题解:

  调了好久233。

  大概想一想就是树分,然后考虑这样路径(u,v)的特征,以根节点(root)切开,u到root的阴阳差值,和v到root巧合互为相反数,然后考虑要有一个点可作为休息点,即u/v到root的路径中要有一点x与u/v到root的阴阳差值相同,然后维护一下就好。

  注意的是阴阳差为0的特判……写挂了调好久,对拍也不好写,真是恶心。

代码:

  

  1 #define Troy 11/23
  2 #define inf 0x7fffffff
  3
  4 #include <bits/stdc++.h>
  5
  6 using namespace std;
  7
  8 inline int read(){
  9     int s=0,k=1;char ch=getchar();
 10     while(ch<‘0‘|ch>‘9‘)    ch==‘-‘?k=-1:0,ch=getchar();
 11     while(ch>47&ch<=‘9‘)    s=s*10+(ch^48),ch=getchar();
 12     return s*k;
 13 }
 14
 15 const int N=1e5+10;
 16
 17 typedef long long ll;
 18
 19 int n;
 20
 21 struct edges{
 22     int v,w;edges *last;
 23 }edge[N<<1],*head[N];int cnt;
 24
 25 inline void push(int u,int v,int w){
 26     edge[++cnt]=(edges){v,w,head[u]};head[u]=edge+cnt;
 27 }
 28
 29 int tot,root,heavy[N],size[N],top,num,T[N<<1][2],nT[N<<1],pre[N<<1];
 30
 31 ll ans,t[N<<1][2];
 32
 33 bool vis[N];
 34
 35 inline void dfs(int x,int fa){
 36     size[x]=1,heavy[x]=0;
 37     for(edges *i=head[x];i;i=i->last)if(!vis[i->v]&&i->v!=fa){
 38         dfs(i->v,x);
 39         heavy[x]=max(heavy[x],size[i->v]);
 40         size[x]+=size[i->v];
 41     }
 42     heavy[x]=max(heavy[x],tot-size[x]);
 43     if(top>heavy[x])
 44         top=heavy[x],root=x;
 45 }
 46
 47 #define g(s) t[s+n]
 48 #define G(s) T[s+n]
 49 #define f(s) pre[s+n]
 50
 51 inline void update(int x,int s,int fa){
 52     bool a=f(s)>0;
 53     if(G(s)[a]!=num)
 54         G(s)[a]=num,g(s)[a]=0;
 55     ++g(s)[a];
 56     ++f(s);
 57     for(edges *i=head[x];i;i=i->last)if(!vis[i->v]&&i->v!=fa)
 58         update(i->v,s+(i->w?1:-1),x);
 59     --f(s);
 60 }
 61
 62 inline void calc(int x,int s,int fa){
 63     bool a=f(s)>0;
 64     ++f(s);
 65     if(G(s)[1]==num)
 66         ans+=g(s)[1];
 67     if(a&&G(s)[0]==num){
 68         ans+=g(s)[0];
 69         if(!s&&f(s)<=2)    ans-=g(s)[0];
 70     }
 71     for(edges *i=head[x];i;i=i->last)if(!vis[i->v]&&i->v!=fa)
 72         calc(i->v,s+(i->w?-1:1),x);
 73     --f(s);
 74 }
 75 inline void solve(int x){
 76     top=inf;
 77     dfs(x,x);
 78     vis[x=root]=true;
 79     G(0)[0]=++num;
 80     g(0)[0]=1;
 81     for(edges *i=head[x];i;i=i->last)if(!vis[i->v]){
 82         calc(i->v,i->w?-1:1,x);
 83         update(i->v,i->w?1:-1,x);
 84     }
 85     for(edges *i=head[x];i;i=i->last)if(!vis[i->v]){
 86         tot=size[i->v];
 87         solve(i->v);
 88     }
 89 }
 90
 91 int main(){
 92     n=read();
 93     for(int i=1,u,v,w;i^n;++i){
 94         u=read(),v=read(),w=read();
 95         push(u,v,w);
 96         push(v,u,w);
 97     }
 98     tot=n;
 99     f(0)=1;
100     solve(1);
101     printf("%lld\n",ans);
102 } 
时间: 2024-08-30 06:33:57

【BZOJ 3697】采药人的路径的相关文章

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

Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径.采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的.他想知道他一共可以选择多少种不同的路径. Input 第1

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

点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. 然而这实在是太傻逼了,黄学长教做人:从父亲来更新儿子,走到一个节点直接更新路径的统计数,反正我们要的是[经过root的xx路径的数量] 所以可以一遍dfs直接搞出来…… 2.统计方案的方式也想错了……我只考虑了以root作为中转站的路径,然而经过root的路径中,并不只有这种路径是合法的……中转站在

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

3697: 采药人的路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 681  Solved: 246[Submit][Status][Discuss] Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径.

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

[BZOJ3697]采药人的路径 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径.采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的.他想知道他一共可以选择多少种

P4930「FJ2014集训」采药人的路径

题目:P4930「FJ2014集训」采药人的路径 思路: 这篇不算题解,是让自己复习的,什么都没说清楚. 很久没有写点分治了,以前为了赶课件学的太急,板子都没打对就照着题解写题,导致学得很不扎实. 这道题差不多是在郭老师的指导下一点点凑出来的,还是没能自己完整写出一道题,惭愧. 这道题大意是:给出一棵边权为0/1的树,求满足以下条件的路径总数:0的个数等于1的个数,且路径上存在一点到路径两端也满足该条件. 这种求路径总数的题,可以想到用点分治. 把0看作-1,就可以转化为路径边权和为0. 如果没

bzoj 3697

终于自己独立A了一道点分治. 点分治的题目和树规的题目很像,都是在树上乱搞,但点分治一般和路径更相关,如果用树规做会感觉冗余状态太多,内存和时间都无法承受,如果不用动态规划,直接在原树上运用这道题的方法,又无法保证时间复杂度(点分治让我们的算法对原树的形态依赖更小,可以保证时间复杂度). 1 /************************************************************** 2 Problem: 3697 3 User: idy002 4 Langua

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

题目 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径.采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的.他想知道他一共可以选择多少种不同的路径. 输入格式 第1行包含一个整数N.

【bzoj3697】采药人的路径 树的点分治

题目描述 给出一棵 $n$ 个点的树,每条边的边权为1或0.求有多少点对 $(i,j)$ ,使得:$i$ 到 $j$ 的简单路径上存在点 $k$ (异于 $i$ 和 $j$ ),使得 $i$ 到 $k$ 的简单路径上0和1数目相等,$j$ 到 $k$ 的简单路径上0和1数目也相等. 输入 第1行包含一个整数N.接下来N-1行,每行包含三个整数a_i.b_i和t_i,表示这条路上药材的类型. 输出 输出符合采药人要求的路径数目. 样例输入 71 2 03 1 12 4 05 2 06 3 15 7

BZOJ3697 采药人的路径

点分治...尼玛啊!蒟蒻怎么做的那么桑心%>_<% Orz hzwer 蒟蒻就补充一下hzwer没讲的东西: (1)对于阴性的植物权值设为-1,阳性的设为+1 (2)最后一段就是讲如何利用新的子树的f[]值求出ans和更新g[] 1 /************************************************************** 2 Problem: 3697 3 User: rausen 4 Language: C++ 5 Result: Accepted 6