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; }
相关文章推荐
- LOJ #6119. 「2017 山东二轮集训 Day7」国王
- loj6102 「2017 山东二轮集训 Day1」第三题
- LOJ #6077. 「2017 山东一轮集训 Day7」逆序对
- 【LOJ6077】「2017 山东一轮集训 Day7」逆序对 生成函数+组合数+DP
- LOJ 6100 「2017 山东二轮集训 Day1」第一题
- LOJ #6077. 「2017 山东一轮集训 Day7」逆序对
- [费用流]LOJ#6079. 「2017 山东一轮集训 Day7」养猫
- [容斥 DP] LOJ#6077. 「2017 山东一轮集训 Day7」逆序对
- loj6100 「2017 山东二轮集训 Day1」第一题
- 2017暑假七林集训day7——花翻
- [Hall定理 + 线段树] LibreOJ#6062. 「2017 山东一轮集训 Day2」Pair
- #6042. 「雅礼集训 2017 Day7」跳蚤王国的宰相
- [线段树][二分图 霍尔定理]LOJ#6062 && 2017 山东一轮集训 Day2. Pair
- [后缀自动机 DP] LOJ#6071. 「2017 山东一轮集训 Day5」字符串
- [DP][倍增NTT]LOJ#6059. 2017 山东一轮集训 Day1. Sum
- [计数][容斥] LOJ#6065 || BZOJ4927 && 2017 山东一轮集训 Day3. 第一题
- 【分块+回文自动机】LibreOJ6070(2017 山东一轮集训 Day4)[基因]题解
- [主席树 链剖] LOJ#6073. 「2017 山东一轮集训 Day5」距离
- [霍尔定理]「2017 山东一轮集训 Day2」LOJ 6062——PAIR
- #6043. 「雅礼集训 2017 Day7」蛐蛐国的修墙方案