「CSP-S 2019」树的重心
考场上送$75pts$真实良心,正解不难;考虑直接对于每一个点算割掉多少条边能使得这个点成为重心,不难发现对于一个不是重心的点,我们要割掉的那条边一定在那个大于$\lfloor \frac{2} \rfloor$的子树里面,而最大子树割掉之后可能就不是最大的了,但新的最大子树只可能是原来的次大子树,推一下柿子要割掉的子树大小需要在$[2A-n,n-2B]$之间,其中$A$为最大子树,$B$为次大子树
于是我们先求一个重心作为根,这样所有非重心节点的最大子树就会跨过这个根,在dfs的过程就能更新子树的大小,用树状数组维护一下就好了,由于需要排除子树内部的情况,所以还需要一个线段树合并;至于重心节点不超过两个,暴力求一下就好
代码
#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=3e5+5;
const int M=maxn*25;
int l[M],r[M],d[M];
struct E{int v,nxt;}e[maxn<<1];
int T,n,num,__,cnt;LL ans=0;
int head[maxn],sum[maxn],rt[maxn],mx[maxn],c[maxn],t[maxn],sz[maxn],col[maxn];
inline void add(int x,int v) {
for(re int i=x;i<=n;i+=i&(-i)) c[i]+=v;
}
inline int ask(int x) {
int nw=0;
for(re int i=x;i;i-=i&(-i)) nw+=c[i];
return nw;
}
inline void add_E(int x,int y) {
e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
void Dfs(int x,int fa) {
sum[x]=1;mx[x]=0;
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa) continue;
Dfs(e[i].v,x);sum[x]+=sum[e[i].v];mx[x]=max(mx[x],sum[e[i].v]);
}
mx[x]=max(n-sum[x],mx[x]);
}
int ins(int nw,int x,int y,int pos) {
if(!nw) nw=++cnt,d[nw]=l[nw]=r[nw]=0;d[nw]++;
if(x==y) return nw;
int mid=x+y>>1;
if(pos<=mid) l[nw]=ins(l[nw],x,mid,pos);
else r[nw]=ins(r[nw],mid+1,y,pos);
return nw;
}
int merge(int a,int b,int x,int y) {
if(!a||!b) return a|b;
if(x==y) {
d[a]+=d[b];
return a;
}
int mid=x+y>>1;
l[a]=merge(l[a],l[b],x,mid);r[a]=merge(r[a],r[b],mid+1,y);
d[a]=d[l[a]]+d[r[a]];return a;
}
int query(int nw,int x,int y,int lx,int ry) {
if(!nw||lx>ry) return 0;
if(lx<=x&&ry>=y) return d[nw];
int mid=x+y>>1,h=0;
if(lx<=mid) h+=query(l[nw],x,mid,lx,ry);
if(ry>mid) h+=query(r[nw],mid+1,y,lx,ry);
return h;
}
void dfs(int x,int fa) {
rt[x]=ins(rt[x],1,n,sz[x]);
if(fa) add(sz[fa],-1),add(n-sz[x],1);
for(re int i=head[x];i;i=e[i].nxt)
if(e[i].v!=fa) dfs(e[i].v,x),rt[x]=merge(rt[x],rt[e[i].v],1,n);
if(mx[x]+mx[x]>n) {
int k=0;
if(mx[x]-t[x]>=2*mx[x]-n) k=ask(mx[x]-t[x])-ask(2*mx[x]-n-1);
if(mx[x]-t[x]<n-2*t[x]) k+=ask(n-2*t[x])-ask(mx[x]-t[x]);
k-=query(rt[x],1,n,2*mx[x]-n,mx[x]-t[x]);
k-=query(rt[x],1,n,mx[x]-t[x]+1,n-2*t[x]);
ans+=1ll*k*x;
}
if(fa) add(sz[fa],1),add(n-sz[x],-1);
}
void Dfs_(int x,int fa) {
sz[x]=1,t[x]=0;
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa) continue;
Dfs_(e[i].v,x);sz[x]+=sz[e[i].v];t[x]=max(t[x],sz[e[i].v]);
}
}
void DFs(int x,int fa,int cm) {
col[x]=cm;sz[x]=1;
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==fa) continue;
DFs(e[i].v,x,cm);sz[x]+=sz[e[i].v];
}
}
void solve(int Rt) {
int col_num=1,A=0,B=0;
for(re int i=head[Rt];i;i=e[i].nxt,col_num++) {
DFs(e[i].v,Rt,col_num);
if(sz[e[i].v]>=sz[A]) B=A,A=e[i].v;
else if(sz[e[i].v]>sz[B]) B=e[i].v;
}
for(re int i=1;i<=n;i++) {
if(i==Rt) continue;
if(col[i]!=col[A]&&2*sz[A]<=(n-sz[i])) ans+=Rt;
if(col[i]==col[A]&&2*max(sz[A]-sz[i],sz[B])<=(n-sz[i])) ans+=Rt;
}
}
int main() {
T=read();
for(re int Rt;T;--T) {
cnt=0;ans=0;n=read(),num=0,__=0;memset(head,0,sizeof(head));memset(rt,0,sizeof(rt));memset(c,0,sizeof(c));
for(re int x,y,i=1;i<n;i++) x=read(),y=read(),add_E(x,y),add_E(y,x);
Dfs(1,0);for(re int i=1;i<=n;i++) if(mx[i]+mx[i]<=n) Rt=i;
Dfs_(Rt,0);
for(re int i=1;i<=n;i++) add(sz[i],1);dfs(Rt,0);
for(re int i=1;i<=n;i++) if(mx[i]+mx[i]<=n) solve(i);
printf("%lld\n",ans);
}
return 0;
}
「CSP-S 2019」树的重心的更多相关文章
- 【CSP-S 2019】树的重心(重心的性质)
Description 给定一颗 \(n\) 个顶点的树 \(\text T\),共 \(n-1\) 次断边操作,每次将树分为两部分 \(\text T_1, \text T_2\),求: \[\su ...
- 「LOJ 3153」 「JOI Open 2019」三级跳
题面 LOJ 3153 solution 对于任意一对\(A,B\),若区间\([A,B]\)中存在一个数权值大于\(A\)或\(B\),则用这个数来替代\(A\)或\(B\)显然更优. 故只需要考虑 ...
- LOJ#6713. 「EC Final 2019」狄利克雷 k 次根 加强版
题目描述 定义两个函数 \(f, g: \{1, 2, \dots, n\} \rightarrow \mathbb Z\) 的狄利克雷卷积 \(f * g\) 为: \[ (f * g)(n) = ...
- 「WC 2019」数树
「WC 2019」数树 一道涨姿势的EGF好题,官方题解我并没有完全看懂,尝试用指数型生成函数和组合意义的角度推了一波.考场上只得了 44 分也暴露了我在数数的一些基本套路上的不足,后面的 \(\ex ...
- 【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)
[题解]#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT) 之前做这道题不理解,有一点走火入魔了,甚至想要一本近世代数来看,然后通过人类智慧思考后发现, ...
- 「雅礼集训 2017 Day7」跳蚤王国的宰相(树的重心)
题面 来源 「 雅 礼 集 训 2017 D a y 7 」 跳 蚤 王 国 的 宰 相 传 统 2000 m s 1024 M i B {\tt「雅礼集训 2017 Day7」跳蚤王国的 ...
- BZOJ 3510 - 首都 「 $LCT$ 动态维护树的重心」
这题 FlashHu 的优化思路值得借鉴 前置引理 树中所有点到某个点的距离和中,到重心的距离和是最小的. 把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上. 一棵树 ...
- 「NOI2013」树的计数 解题报告
「NOI2013」树的计数 这什么神题 考虑对bfs重新编号为1,2,3...n,然后重新搞一下dfs序 设dfs序为\(dfn_i\),dfs序第\(i\)位对应的节点为\(pos_i\) 一个暴力 ...
- 「SDOI2017」树点涂色 解题报告
「SDOI2017」树点涂色 我sb的不行了 其实一开始有一个类似动态dp的想法 每个点维护到lct树上到最浅点的颜色段数,然后维护一个\(mx_{0,1}\)也就是是否用虚儿子的最大颜色 用个set ...
随机推荐
- Pyinstaller 打包exe 报错 "failed to execute script XXX"的一种解决方案
最近用PyQt5写了一个界面小程序,需要打包成exe给到其他windows上使用,一开始使用python 3.7 64位,用pyinstaller打包exe,在64位机上运行正常. 但是目标电脑是32 ...
- 死磕Spring源码系列
一.Spring总体架构 1.架构图 2.SpringIOC:核心容器提供 Spring 框架的基本功能.核心容器的主要组件是 BeanFactory,它是工厂模式的实现.BeanFactory 使用 ...
- 使用truelicense实现用于JAVA工程license机制(包括license生成和验证)
开发的软件产品在交付使用的时候,往往会授权一段时间的试用期,这个时候license就派上用场了.不同于在代码中直接加上时间约束,需要重新授权的时候使用license可以避免修改源码,改动部署,授权方直 ...
- Codeforces 1163F 最短路 + 线段树 (删边最短路)
题意:给你一张无向图,有若干次操作,每次操作会修改一条边的边权,每次修改后输出1到n的最短路.修改相互独立. 思路:我们先以起点和终点为根,找出最短路径树,现在有两种情况: 1:修改的边不是1到n的最 ...
- 【Luogu】【关卡2-10】分治算法(2017年10月)
任务说明:将大问题拆分为小问题,分而治之,各个击破,然后在合并回来. 取余运算||快速幂 幂次方 逆序对 南蛮图腾
- 4、Python 基础类型 -- Tuple 元祖类型
Python 元组 Python的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. 如下实例: 实例(P ...
- 当我们在Java中新建一个对象的时候发生了什么?
- Thread.Join理解
Thread.Join:Blocks the calling thread until a thread terminates MainThread里面起了一个SubThread,从SubThread ...
- EcShop二次开发学习方法和Ecshop二次开发必备基础
ecshop二次开发学习方法 近年来,随着互联网的发展,电子商务也跟着一起成长,B2B,C2C,B2C的电子商务模式也不断的成熟.这时催生出了众多电子商务相关的php开源产品.B2C方面有Ecshop ...
- NOIP2019模拟2019.9.20】膜拜大会(外向树容斥,分类讨论)
传送门. 题解: 我果然是不擅长分类讨论,心态被搞崩了. 注意到\(m<=n-2\),意味着除了1以外的位置不可能被加到a[1]两遍. 先考虑个大概: 考虑若存在\(x,x-1,-,2\)(有序 ...