BZOJ 3697: 采药人的路径 点分治
2017-12-03 12:00
387 查看
3697: 采药人的路径
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1329 Solved: 453
[Submit][Status][Discuss]
Description
采药人的药田是一个树状结构,每条路径上都种植着同种药材。采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。
Input
第1行包含一个整数N。接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。
Output
输出符合采药人要求的路径数目。Sample Input
71 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
Sample Output
1HINT
对于100%的数据,N ≤ 100,000。想到点分治应该是很快的
那么考虑枚举的分治根
我是先考虑分治根作为分割点的情况
发现这样无法保证答案正确
那就还是老套路 分治根解决经过分治根的路径
发现 ..靠有点长
那就...黄学长使我们的红太阳!!
传送门:【bzoj3697】【FJ2014集训】采药人的路径
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}
const int N=100100,inf=0X3f3f3f3f;
int last
,ecnt;
struct EDGE{int to,nt,val;}e[N<<1];
inline void add(int u,int v,int val)
{e[++ecnt]=(EDGE){v,last[u],val};last[u]=ecnt;}
int n;
ll ans;
int root,sum;
int dep
,size
,wgt
;
bool vis
;
void getroot(int u,int fa)
{
size[u]=1;wgt[u]=0;
for(int i=last[u],v;i;i=e[i].nt)
if(!vis[(v=e[i].to)]&&v!=fa)
{
getroot(v,u);
size[u]+=size[v];
wgt[u]=max(wgt[u],size[v]);
}
wgt[u]=max(wgt[u],sum-size[u]);
if(wgt[u]<wgt[root])root=u;
}
int mxd;
int dis
;
int f[N<<1][2],g[N<<1][2];
int book[N<<1];
void dfs(int u,int fa)
{
mxd=max(mxd,dep[u]);
book[dis[u]] ? f[dis[u]][1]++ : f[dis[u]][0]++;
book[dis[u]]++;
for(int i=last[u],v;i;i=e[i].nt)
if(!vis[(v=e[i].to)]&&v!=fa)
{
dep[v]=dep[u]+1;
dis[v]=dis[u]+e[i].val;
dfs(v,u);
}
book[dis[u]]--;
}
void cal(int u)
{
int mx=0;
g
[0]=1;
for(int i=last[u],v;i;i=e[i].nt)
if(!vis[(v=e[i].to)])
{
dep[v]=mxd=1;
dis[v]=n+e[i].val;
dfs(v,u);
mx=max(mx,mxd);
ans+=1ll*(g
[0]-1)*f
[0];
for(int j=-mxd;j<=mxd;++j)
ans+=1ll*g[n-j][1]*f[n+j][1]+1ll*g[n-j][0]*f[n+j][1]+1ll*g[n-j][1]*f[n+j][0];
for(int j=n-mxd;j<=n+mxd;++j)
{
g[j][0]+=f[j][0];
g[j][1]+=f[j][1];
f[j][0]=f[j][1]=0;
}
}
for(int i=n-mx;i<=n+mx;++i)
g[i][0]=g[i][1]=0;
}
void solve(int u)
{
vis[u]=1;
cal(u);
for(int i=last[u],v;i;i=e[i].nt)
if(!vis[(v=e[i].to)])
{
root=0;sum=size[v];
getroot(v,u);
solve(root);
}
}
int main()
{
n=read();
register int i,u,v,val;
for(i=1;i<n;++i)
{
u=read();v=read();val=read();
if(!val)val--;
add(u,v,val);add(v,u,val);
}
sum=n;wgt[0]=inf;
getroot(1,0);
solve(root);
cout<<ans<<endl;
return 0;
}
/*
7
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
1
*/
相关文章推荐
- BZOJ 3697 采药人的路径 树的点分治
- bzoj 3697: 采药人的路径 点分治
- BZOJ3697 采药人的路径 【点分治】
- 【bzoj3697】采药人的路径 点分治
- 【bzoj3697】【采药人的路径】【点分治】
- 【BZOJ3697】采药人的路径【点分治】
- [bzoj3697]采药人的路径——点分治
- 【BZOJ3697】采药人的路径(点分治)
- BZOJ 3697 采药人的路径 点分治
- [BZOJ3697][[FJ2014集训]采药人的路径][点分治]
- [BZOJ3697]采药人的路径(点分治)
- 【BZOJ 3697】采药人的路径 树上点分治
- BZOJ_3697_采药人的路径_点分治
- BZOJ 3697: 采药人的路径 树的点分治
- bzoj3697 采药人的路径 (点分治)
- BZOJ 3697: 采药人的路径 [点分治] [我想上化学课]
- 【BZOJ3697】采药人的路径 点分治
- bzoj 3697: 采药人的路径 (点分治)
- 【bzoj3697】【坑】采药人的路径 点分治
- [BZOJ3697]采药人的路径(点分治)