您的位置:首页 > 其它

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

2018-03-08 13:51 591 查看

题目描述

在某个神奇的大陆上,有一个国家,这片大陆的所有城市间的道路网可以看做是一棵树,每个城市要么是工业城市,要么是农业城市,这个国家的人认为一条路径是 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]$。

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

#include <bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define N (500005)

using namespace std;

struct edge{ int nt,to; }g
;
struct data{ int i,l; }st
;

int head
,tong
,vis
,dis
,son
,sz
,a
,n,num,top;
ll f
,now,sum,ans;

il int gi(){
RG int x=0,q=1; RG char ch=getchar();
while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if (ch=='-') q=-1,ch=getchar();
while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return q*x;
}

il void insert(RG int from,RG int to){
g[++num]=(edge){head[from],to},head[from]=num; return;
}

il void getrt(RG int x,RG int p,RG int &rt){
son[x]=0,sz[x]=1;
for (RG int i=head[x],v;i;i=g[i].nt){
v=g[i].to; if (v==p || vis[v]) continue;
getrt(v,x,rt),sz[x]+=sz[v],son[x]=max(son[x],sz[v]);
}
son[x]=max(son[x],son[0]-sz[x]);
if (son[rt]>=son[x]) rt=x; return;
}

il void getdis(RG int x,RG int p){
dis[x]=dis[p]+a[x],st[++top]=(data){x,dis[x]},sz[x]=1;
for (RG int i=head[x],v;i;i=g[i].nt){
v=g[i].to; if (v==p || vis[v]) continue;
getdis(v,x),sz[x]+=sz[v];
}
return;
}

il void calc(RG int rt,RG int p,RG int fg){
top=0,getdis(rt,p);
for (RG int i=1;i<=top;++i) ++tong[n+st[i].l];
for (RG int i=1,res;i<=top;++i)
res=fg*tong[n+(p?a[p]:a[rt])-st[i].l],sum+=res,f[st[i].i]+=res;
for (RG int i=1;i<=top;++i) --tong[n+st[i].l]; return;
}

il void solve(RG int x,RG int S){
RG int rt=0; son[0]=S,getrt(x,0,rt);
vis[rt]=1,dis[rt]=a[rt],calc(rt,0,1);
for (RG int i=head[rt];i;i=g[i].nt)
if (!vis[g[i].to]) calc(g[i].to,rt,-1);
for (RG int i=head[rt];i;i=g[i].nt)
if (!vis[g[i].to]) solve(g[i].to,sz[g[i].to]);
return;
}

int main(){
#ifndef ONLINE_JUDGE
freopen("king.in","r",stdin);
freopen("king.out","w",stdout);
#endif
n=gi();
for (RG int i=1;i<=n;++i) a[i]=gi()?1:-1;
for (RG int i=1,u,v;i<n;++i)
u=gi(),v=gi(),insert(u,v),insert(v,u);
solve(1,n);
for (RG int i=1,j=1;i<=n;++i){
now+=f[i]; while (j<=i && now<<1>sum) now-=f[j++];
ans+=j-1;
}
cout<<ans; return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: