您的位置:首页 > 运维架构

【USACO 2013 open】【JZOJ 3234】阴阳

2016-06-13 20:50 302 查看

Description

Farmer John 正在在计划自己的农场漫步。他的农场的结构就像一棵树:农场有N个谷仓(1<= N <=100,000),分别由N-1条路链接。这样,他便可以通过这些谷仓间的道路遍及各个谷仓。Farmer John想要选择一条路线:这条路线的起点和终点分别为农场中两个不同的谷仓,这条路线不能重复经过一条边两次。Farmer John担心这条路径可能会偏长,所以他想在路线上寻找一个休息点(当然这个休息点不能为起点或者终点)。

每条边的两旁都是牛群,要么是Charcolais(白毛),要么是Angus(黑毛)。Farmer John是一个聪明人,所以他想要在他通过小路的同时平衡小路两侧阴阳的力量。他要选择一条路径使得他从起点到休息站,和从休息站到终点这两段路上都满足路两边的Charcolais牛群和Angus牛群总数量相同。

Farmer John好奇他能找到多少条如上所述的平衡的路径。我们认为,当且仅当两条路线的边的集合不同时,这两条路径才被认为是不同的,否则认为是相同的路线。就算路线上有多个有效的“休息站”的位置能使路线平衡,我们也只记为一条路线。

请帮助计算有多少条不同的平衡路线。

Solution

很显然这是一道点分治,

白毛为1,黑毛为-1,

我们每轮的点分治表示过重心的合法路径,(以下的距离指与根节点的路径和)

设Cs表示之前从根出发第一次遇到距离为s的点的个数,cs为之前从根出发非第一次(也就是存在父亲(包括根)的和也为s)遇到距离为s的点的个数,当前的点为q,距离为s,

q对答案的贡献至少为cs,如果当前点存在父亲距离也等于s,那么还要加上Cs,因为我们必须找一个点作为休息点,

每轮更新一下数组即可

复杂的:O(2∗nlog(n));

Code

#include<iostream>
#include<cstdlib>
#include<cstdio>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int N=100500,maxlongint=2147483640;
int read(int &n)
{
n=0;int q=0,w=1;char ch=getchar();
for(;(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0'&&ch<='9';q=q*10+ch-48,ch=getchar());
n=q*w;return n;
}
int B[2*N][3],A
,B0;
int n,hw
,c[2*N],c1[2*N];
LL ans;
int alln,ce,ces,z[2*N];
bool bj
;
void join(int q,int w,int e)
{
B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w,B[B0][2]=e;
B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q,B[B0][2]=e;
}
int dfs(int q,int fa)
{
int w;hw[q]=1;
for(int i=A[q];i;i=B[i][0])if(!bj[w=B[i][1]]&&fa!=w)hw[q]+=dfs(w,q);
return hw[q];
}
void findc(int q,int fa)
{
int s=alln-hw[q],w;
for(int i=A[q];i;i=B[i][0])if(!bj[w=B[i][1]]&&fa!=w)findc(w,q),s=max(s,hw[B[i][1]]+1);
if(ces>s)ces=s,ce=q;
}
void add(int q,int s0,int fa)
{
c[s0+N]+=(z[s0+N]!=0);c1[s0+N]+=(z[s0+N]==0);z[s0+N]++;
for(int i=A[q];i;i=B[i][0])if(!bj[B[i][1]]&&fa!=B[i][1])add(B[i][1],s0+B[i][2],q);
z[s0+N]--;
}
void find(int q,int s0,int fa)
{
ans+=c[N-s0]+(z[s0+N]!=0)*c1[N-s0];
z[s0+N]++;
for(int i=A[q];i;i=B[i][0])if(!bj[B[i][1]]&&fa!=B[i][1])find(B[i][1],s0+B[i][2],q);
z[s0+N]--;
}
void divide(int q)
{
alln=dfs(q,q);
ces=maxlongint;
findc(q,q);bj[q=ce]=1;
fill(c+N-alln-1,c+N+alln+1,0);fill(c1+N-alln-1,c1+N+alln+1,0);c1
=1;
for(int i=A[q];i;i=B[i][0])if(!bj[B[i][1]])
{
z
=0;find(B[i][1],B[i][2],q);
z
=1;add(B[i][1],B[i][2],q);
}
for(int i=A[q];i;i=B[i][0])if(!bj[B[i][1]])divide(B[i][1]);
}
int main()
{
int q,w,e;
read(n);
fo(i,1,n-1)read(q),read(w),read(e),join(q,w,(e?1:-1));
ans=0;
divide(1);
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: