考虑枚举一个点k,求其为重心的方案数
暴力的做法是,将其作为根搜索,设最大子树大小为s1,次大为s2,对割掉的子树分类讨论:
1.在子树中,分两种情况(都可以用线段树合并来做)
 (1)从s1中切掉一棵大小为s3的子树,应该满足$2max(s2,s1-s3)\le n-s3$,即$2s1-n\le s3\le n-2s2$
 (2)从其他子树中切掉一棵大小为s3的子树,应该满足$2s1\le n-s3$,即$s3\le n-2s1$
2.是父亲,那么割掉的边再分为两类(这些东西也需要再根据父亲是不是最大子树来讨论)
 (1)割掉的边是直接到根的路径,那么割掉的子树大小s3就是n-割出来的子树,可以再搜一遍不断的维护当前节点到根的路径上所有子树大小,用权值线段树来维护区间和
 (2)割掉的边是其他边,直接对最终线段树合并到根的线段树上查询即可(注意这样会错误计算第(1)种情况,要注意在第一个中抵消掉,即再对子树大小打上-1标记)

  1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 300005
4 #define mid (l+r>>1)
5 struct ji{
6 int nex,to;
7 }edge[N<<1];
8 struct node{
9 int sum,ls,rs;
10 }f[N*50];
11 int E,V,t,n,x,y,head[N],r[N],fi[N],se[N],sz[N];
12 long long ans;
13 void up(int k){
14 f[k].sum=f[f[k].ls].sum+f[f[k].rs].sum;
15 }
16 void update(int &k,int l,int r,int x,int y){
17 if (!k)k=++V;
18 if (l==r){
19 f[k].sum+=y;
20 return;
21 }
22 if (x<=mid)update(f[k].ls,l,mid,x,y);
23 else update(f[k].rs,mid+1,r,x,y);
24 up(k);
25 }
26 int query(int k,int l,int r,int x,int y){
27 if ((!k)||(l>y)||(x>r))return 0;
28 if ((x<=l)&&(r<=y))return f[k].sum;
29 return query(f[k].ls,l,mid,x,y)+query(f[k].rs,mid+1,r,x,y);
30 }
31 int merge(int k1,int k2){
32 if ((!k1)||(!k2))return k1+k2;
33 if ((!f[k1].ls)&&(!f[k1].rs)){
34 f[k1].sum+=f[k2].sum;
35 return k1;
36 }
37 f[k1].ls=merge(f[k1].ls,f[k2].ls);
38 f[k1].rs=merge(f[k1].rs,f[k2].rs);
39 up(k1);
40 return k1;
41 }
42 void add(int x,int y){
43 edge[E].nex=head[x];
44 edge[E].to=y;
45 head[x]=E++;
46 }
47 void dfs(int k,int fa){
48 fi[k]=sz[k]=0;
49 sz[k]=1;
50 for(int i=head[k];i!=-1;i=edge[i].nex)
51 if (edge[i].to!=fa){
52 dfs(edge[i].to,k);
53 sz[k]+=sz[edge[i].to];
54 if (sz[edge[i].to]<fi[k])se[k]=max(se[k],sz[edge[i].to]);
55 else{
56 se[k]=fi[k];
57 fi[k]=sz[edge[i].to];
58 }
59 }
60 if (n-sz[k]<fi[k])se[k]=max(se[k],n-sz[k]);
61 else{
62 se[k]=fi[k];
63 fi[k]=n-sz[k];
64 }
65 for(int i=head[k];i!=-1;i=edge[i].nex)
66 if (edge[i].to!=fa){
67 if (sz[edge[i].to]!=fi[k])ans+=1LL*k*query(r[edge[i].to],1,n,1,n-2*fi[k]);
68 else ans+=1LL*k*query(r[edge[i].to],1,n,max(2*fi[k]-n,1),n-2*se[k]);
69 r[k]=merge(r[k],r[edge[i].to]);
70 }
71 if (fi[k]!=n-sz[k])ans-=1LL*k*query(r[k],1,n,1,n-2*fi[k]);
72 else ans-=1LL*k*query(r[k],1,n,max(2*fi[k]-n,1),n-2*se[k]);
73 update(r[k],1,n,sz[k],1);
74 }
75 void dfs2(int k,int fa){
76 update(r[1],1,n,sz[k],-1);
77 if (k>1)update(r[1],1,n,n-sz[k],1);
78 if (fi[k]!=n-sz[k])ans+=1LL*k*query(r[1],1,n,1,n-2*fi[k]);
79 else ans+=1LL*k*query(r[1],1,n,max(2*fi[k]-n,1),n-2*se[k]);
80 for(int i=head[k];i!=-1;i=edge[i].nex)
81 if (edge[i].to!=fa)dfs2(edge[i].to,k);
82 update(r[1],1,n,sz[k],1);
83 update(r[1],1,n,n-sz[k],-1);
84 }
85 int main(){
86 scanf("%d",&t);
87 while (t--){
88 E=V=ans=0;
89 memset(r,0,sizeof(r));
90 memset(f,0,sizeof(f));
91 memset(head,-1,sizeof(head));
92 scanf("%d",&n);
93 for(int i=1;i<n;i++){
94 scanf("%d%d",&x,&y);
95 add(x,y);
96 add(y,x);
97 }
98 dfs(1,0);
99 dfs2(1,0);
100 printf("%lld\n",ans);
101 }
102 }

[luogu5666]树的重心的更多相关文章

  1. POJ3107Godfather[树形DP 树的重心]

    Godfather Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6121   Accepted: 2164 Descrip ...

  2. poj1655 树的重心 树形dp

    树的重心定义为:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡. 处理处每个节点的孩子有几个,和树的大小就好了. #include< ...

  3. poj3107 求树的重心(&& poj1655 同样求树的重心)

    题目链接:http://poj.org/problem?id=3107 求树的重心,所谓树的重心就是:在无根树转换为有根树的过程中,去掉根节点之后,剩下的树的最大结点最小,该点即为重心. 剩下的数的 ...

  4. 树形DP求树的重心 --SGU 134

    令一个点的属性值为:去除这个点以及与这个点相连的所有边后得到的连通分量的节点数的最大值. 则树的重心定义为:一个点,这个点的属性值在所有点中是最小的. SGU 134 即要找出所有的重心,并且找出重心 ...

  5. 求树的重心(POJ1655)

    题意:给出一颗n(n<=2000)个结点的树,删除其中的一个结点,会形成一棵树,或者多棵树,定义删除任意一个结点的平衡度为最大的那棵树的结点个数,问删除哪个结点后,可以让平衡度最小,即求树的重心 ...

  6. codeforces 685B Kay and Snowflake 树的重心

    分析:就是找到以每个节点为根节点的树的重心 树的重心可以看这三篇文章: 1:http://wenku.baidu.com/link?url=yc-3QD55hbCaRYEGsF2fPpXYg-iO63 ...

  7. POJ 1655 Balancing Act (求树的重心)

    求树的重心,直接当模板吧.先看POJ题目就知道重心什么意思了... 重心:删除该节点后最大连通块的节点数目最小 #include<cstdio> #include<cstring&g ...

  8. POJ3107--Godfather(树的重心)

    vector建图被卡了..改为链式前向星500ms过的..差了四倍多?... 表示不太会用链表建图啊..自己试着写的,没看模板..嗯..果然错了..落了一句话orz 树的重心就是找到一个树中一个点,其 ...

  9. POJ 1655 Balancing Act&&POJ 3107 Godfather(树的重心)

    树的重心的定义是: 一个点的所有子树中节点数最大的子树节点数最小. 这句话可能说起来比较绕,但是其实想想他的字面意思也就是找到最平衡的那个点. POJ 1655 题目大意: 直接给你一棵树,让你求树的 ...

随机推荐

  1. hd-cg辉度通用代码生成器

    HD-CG 辉度通用代码生成器 主要特点: 1. 自定义代码模板:通过简单的默认变量自行编写代码模板,如果默认变量不满足需求,也可增加自定义变量. 2. 自定义数据源:可自定义添加多个项目的数据库,数 ...

  2. asp.net core使用identity+jwt保护你的webapi(二)——获取jwt token

    前言 上一篇已经介绍了identity在web api中的基本配置,本篇来完成用户的注册,登录,获取jwt token. 开始 开始之前先配置一下jwt相关服务. 配置JWT 首先NuGet安装包: ...

  3. linux启动redis命令

    首先进入到/usr/local/bin目录下(因为你redis安装的目录绝大多数都在这里) root@xxxx:/usr/local/bin#:redis-server wangconfig/redi ...

  4. springcloud整合config组件

    config组件 config组件支持两种配置文件获取方式springcould搭建的微服务的配置文件的获取方式有两种.它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中或者本地 ...

  5. AES解密尾部出现乱码问题

    说明 在使用AES解密的时候我发现解密出来的字符串尾部一直都有乱码 解决方案 尾部字符串的ascii码就是删除位索引 具体代码: cryptor = AES.new('AES_KEY'.encode( ...

  6. 手摸手教你用 yapi-to-typescript生成Yapi的TypeScript数据类型

    一 背景 现代社会比较重视效率,本着这个思想宗旨,能用工具自动高效做的事情,就不要低质量的勤奋.yapi-to-typescript就是一款自动生成接口请求与响应的typescript数据类型定义的工 ...

  7. 分库分表利器之Sharding Sphere(深度好文,看过的人都说好)

    Sharding-Sphere Sharding-JDBC 最早是当当网内部使用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名为 S ...

  8. Prometheus基于文件的服务发现

    Prometheus基于文件的服务发现 一.基于文件的服务发现 1.prometheus.yml 配置文件的写法 2.file_sd 目录下的文件 3.配置结果 二.注意事项 三.参考链接 一.基于文 ...

  9. FastAPI 学习之路(二十八)使用密码和 Bearer 的简单 OAuth2

    OAuth2 规定在使用(我们打算用的)「password 流程」时,客户端/用户必须将 username 和 password 字段作为表单数据发送.我们看下在我们应该去如何实现呢. 我们写一个登录 ...

  10. 单片机STM32开发中常用库函数分析

    1.GPIO初始化函数 用法: voidGPIO_Configuration(void) { GPIO_InitTypeDefGPIO_InitStructure;//GPIO状态恢复默认参数 GPI ...