【BZOJ-3697&3127】采药人的路径&YinandYang 点分治 + 乱搞
3697: 采药人的路径
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 681 Solved: 246
[Submit][Status][Discuss]
Description
采药人的药田是一个树状结构,每条路径上都种植着同种药材。
采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。
Input
第1行包含一个整数N。
接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。
Output
输出符合采药人要求的路径数目。
Sample Input
7
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
Sample Output
1
HINT
对于100%的数据,N ≤ 100,000。
Source
3127: [Usaco2013 Open]Yin and Yang
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 116 Solved: 82
[Submit][Status][Discuss]
Description
Farns (1 <= N <= 100,000) which are connected by N-1 edges such that
he can reach any barn from any other. Farmer John wants to choose a path which starts and ends at two
different barns, such that he does not traverse any edge twice. He worries that his path might be a
little long, so he also wants to choose another "rest stop" barn located on this path (which is distinct
from the start or the end). Along each edge is a herd of cows, either of the Charcolais (white hair)
or the Angus (black hair) variety. Being the wise man that he is, Farmer John wants to balance the
forces of yin and yang that weigh upon his walk. To do so, he wishes to choose a path such that he
will pass by an equal number of Charcolais herds and Angus herds-- oth on the way from the start to
his rest stop, and on theway from the rest stop to the end. Farmer John is curious how many different
paths he can choose that are "balanced" as described above. Two paths are different only if they
consist of different setsof edges; a path should be counted only once even if there are multiple valid
"rest stop" locationsalong the path that make it balanced. Please help determine the number of
paths Farmer John can cho
Input
* Line 1: The integer N.
* Lines 2..N: Three integers a_i, b_i and t_i, representing the two barns
that edge i connects. t_i
is 0 if the herd along that edge is Charcolais, and 1 if the herd is
Angus.
Output
Line 1: One integer, representing the number of possible paths Farmer John can choose from.
Sample Input
7
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
INPUT DETAILS:
There are 7 barns and 6 edges. The edges from 1 to 2, 2 to 4 and 2 to 5 have Charcolais herds along
them.
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
INPUT DETAILS:
There are 7 barns and 6 edges. The edges from 1 to 2, 2 to 4 and 2 to 5 have Charcolais herds along
them.
Sample Output
1
OUTPUT DETAILS:
No path of length 2 can have a suitable rest stop on it, so we can only consider paths of length 4.
The only path that has a suitable rest stop is 3-1-2-5-7, with a rest stop at 2.
OUTPUT DETAILS:
No path of length 2 can have a suitable rest stop on it, so we can only consider paths of length 4.
The only path that has a suitable rest stop is 3-1-2-5-7, with a rest stop at 2.
HINT
Source
Solution
这道题有点厉害
首先肯定想到点分治,问题在于如何统计答案
首先对于阴阳边,我们可以赋权值+1/-1,这样路径阴阳数目就比较直观了
定义$f[i][0/1]$表示当前子树中路径和为$i$的路径个数,0/1表示路径上是否存在前缀为$i$的点
定义$g[i][0/1]$表示之前前子树中路径和为$i$的路径个数,0/1同理
那么对答案的贡献就是$g[0][0]*f[0][0]+\sum (g[-i][0]]*f[i][1]+g[-i][1]*f[i][0]+g[-i][1]*f[i][1])$
要注意考虑下标为负的情况...全部+N即可
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 100010 #define LL long long int N; struct EdgeNode{int next,to,val;}edge[MAXN<<1]; int head[MAXN],cnt=1; void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].val=w;} void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);} int size[MAXN],maxx[MAXN],root,Sz; bool visit[MAXN]; void DFSRoot(int now,int last) { size[now]=1; maxx[now]=0; for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=last && !visit[edge[i].to]) { DFSRoot(edge[i].to,now); size[now]+=size[edge[i].to]; maxx[now]=max(maxx[now],size[edge[i].to]); } maxx[now]=max(maxx[now],Sz-size[now]); if (maxx[now]<maxx[root]) root=now; } int deep[MAXN],maxd,md,mark[MAXN<<1],D[MAXN<<1]; LL f[MAXN<<1][2],g[MAXN<<1][2],ans; void DFS(int now,int last) { maxd=max(maxd,deep[now]); if (mark[D[now]]) f[D[now]][1]++; else f[D[now]][0]++; mark[D[now]]++; for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=last && !visit[edge[i].to]) { deep[edge[i].to]=deep[now]+1; D[edge[i].to]=D[now]+edge[i].val; DFS(edge[i].to,now); } mark[D[now]]--; } void Get(int x,int val) { D[x]=N+val; deep[x]=1; maxd=1; DFS(x,0); md=max(maxd,md); ans+=(g[N][0]-1)*f[N][0]; for (int i=-maxd; i<=maxd; i++) ans+=g[N-i][1]*f[N+i][1]+g[N-i][0]*f[N+i][1]+g[N-i][1]*f[N+i][0]; for (int i=N-maxd; i<=N+maxd; i++) g[i][0]+=f[i][0],g[i][1]+=f[i][1],f[i][0]=f[i][1]=0; } void Divide(int x) { visit[x]=1; g[N][0]=1; md=0; for (int i=head[x]; i; i=edge[i].next) if (!visit[edge[i].to]) Get(edge[i].to,edge[i].val); for (int i=-md; i<=md; i++) g[N+i][0]=g[N+i][1]=0; for (int i=head[x]; i; i=edge[i].next) if (!visit[edge[i].to]) { Sz=size[edge[i].to]; root=0; DFSRoot(edge[i].to,x); Divide(root); } } int main() { N=read(); for (int x,y,z,i=1; i<=N-1; i++) x=read(),y=read(),z=read(),InsertEdge(x,y,z? z:-1); Sz=maxx[root=0]=N; DFSRoot(1,0); Divide(root); printf("%lld\n",ans); return 0; }
——It's a lonely path. Don't make it any lonelier than it has to be.