loj6119 「2017 山东二轮集训 Day7」国王

题目描述

在某个神奇的大陆上,有一个国家,这片大陆的所有城市间的道路网可以看做是一棵树,每个城市要么是工业城市,要么是农业城市,这个国家的人认为一条路径是 exciting 的,当且仅当这条路径上的工业城市和农业城市数目相等。现在国王想把城市分给他的两个儿子,大儿子想知道,他选择一段标号连续的城市作为自己的领地,并把剩下的给弟弟,能够满足两端都是自己城市的 exciting 路径比两端都是弟弟的城市的 exciting 路径数目多的方案数。

输入格式

第一行一个正整数 n n n。
第二行 n n n 个整数依次描述城市的性质,1 1 1 为工业,0 0 0 为农业。
接下来 n−1 n - 1 n−1 行每行两个正整数描述一条道路。

输出格式

输出一个整数表示答案。

样例

样例输入

5
1 0 1 0 1
1 2
1 3
2 4
2 5

样例输出

5

数据范围与提示

n≤100000 n leq 100000 n≤100000

正解:点分治。

对于每个右端点,我们找出极小的左端点使得在这个区间内大儿子不能获利,显然这是满足单调性的。

然后我们设$A$为两个端点都在区间内的路径数量,$B$为两个端点都在区间外的路径数量,如果$A>B$,那么左端点就可以往右移。

设$C$为两个端点分别在区间内外的答案,我们发现$2A+C>2B+C$与前面的不等式是等价的。

设$sum$为总路径数$*2$,$f[i]$为一个端点为$i$的路径数量,那么$2A+C=sum_{i=l}^{r}f[i]$,$2B+C=sum-sum_{i=l}^{r}f[i]$。

然后用点分治来统计一下路径就行了。。

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define N (500005)
 6 
 7 using namespace std;
 8 
 9 struct edge{ int nt,to; }g[N];
10 struct data{ int i,l; }st[N];
11 
12 int head[N],tong[N],vis[N],dis[N],son[N],sz[N],a[N],n,num,top;
13 ll f[N],now,sum,ans;
14 
15 il int gi(){
16   RG int x=0,q=1; RG char ch=getchar();
17   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
18   if (ch=='-') q=-1,ch=getchar();
19   while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
20   return q*x;
21 }
22 
23 il void insert(RG int from,RG int to){
24   g[++num]=(edge){head[from],to},head[from]=num; return;
25 }
26 
27 il void getrt(RG int x,RG int p,RG int &rt){
28   son[x]=0,sz[x]=1;
29   for (RG int i=head[x],v;i;i=g[i].nt){
30     v=g[i].to; if (v==p || vis[v]) continue;
31     getrt(v,x,rt),sz[x]+=sz[v],son[x]=max(son[x],sz[v]);
32   }
33   son[x]=max(son[x],son[0]-sz[x]);
34   if (son[rt]>=son[x]) rt=x; return;
35 }
36 
37 il void getdis(RG int x,RG int p){
38   dis[x]=dis[p]+a[x],st[++top]=(data){x,dis[x]},sz[x]=1;
39   for (RG int i=head[x],v;i;i=g[i].nt){
40     v=g[i].to; if (v==p || vis[v]) continue;
41     getdis(v,x),sz[x]+=sz[v];
42   }
43   return;
44 }
45 
46 il void calc(RG int rt,RG int p,RG int fg){
47   top=0,getdis(rt,p);
48   for (RG int i=1;i<=top;++i) ++tong[n+st[i].l];
49   for (RG int i=1,res;i<=top;++i)
50     res=fg*tong[n+(p?a[p]:a[rt])-st[i].l],sum+=res,f[st[i].i]+=res;
51   for (RG int i=1;i<=top;++i) --tong[n+st[i].l]; return;
52 }
53 
54 il void solve(RG int x,RG int S){
55   RG int rt=0; son[0]=S,getrt(x,0,rt);
56   vis[rt]=1,dis[rt]=a[rt],calc(rt,0,1);
57   for (RG int i=head[rt];i;i=g[i].nt)
58     if (!vis[g[i].to]) calc(g[i].to,rt,-1);
59   for (RG int i=head[rt];i;i=g[i].nt)
60     if (!vis[g[i].to]) solve(g[i].to,sz[g[i].to]);
61   return;
62 }
63 
64 int main(){
65 #ifndef ONLINE_JUDGE
66   freopen("king.in","r",stdin);
67   freopen("king.out","w",stdout);
68 #endif
69   n=gi();
70   for (RG int i=1;i<=n;++i) a[i]=gi()?1:-1;
71   for (RG int i=1,u,v;i<n;++i)
72     u=gi(),v=gi(),insert(u,v),insert(v,u);
73   solve(1,n);
74   for (RG int i=1,j=1;i<=n;++i){
75     now+=f[i]; while (j<=i && now<<1>sum) now-=f[j++];
76     ans+=j-1;
77   }
78   cout<<ans; return 0;
79 }
原文地址:https://www.cnblogs.com/wfj2048/p/8514695.html