CSP-S 2019 Day 2 T3 树的重心

给出了一个大小为\(n\)的树,树中结点从 1∼n 编号。小简单的课后作业是求出这棵树单独删去每条边后,分裂出的两个子树的重心编号和之和。

\(n\le 10^5\)

思路

计算每一个点对答案单独的贡献。

删除一条边等价于把一个子树分裂出来,这个子树的根节点设为\(v\)。

对于一个点\(x\),大致有以下几种情况。

  • 它在被分裂出来的子树内(此时\(v\)是\(x\)的祖先或就是\(x\))
  • 被分裂出来的子树在\(x\)外
  • 被分裂出来的子树在\(x\)的其他子树内
  • 被分裂出来的子树在\(x\)的重子树内

我们一一来处理一下

对于第一种情况,有可能过重的子树只有两个:\(x\)外的子树和\(x\)的重子树

对于第二种情况,有可能过重的子树只有两个:\(x\)外的子树和\(x\)的重子树

对于第三种情况,有可能过重的子树只有两个:\(x\)外的子树和\(x\)的重子树

对于第四种情况,,有可能过重的子树只有三个:\(x\)外的子树,\(x\)的重子树\(x\)的次重子树

列出对应的不等式,可以发现\(siz_v\)的取值有一个范围

另外\(v\)处在哪里还会有一些限制

把一个范围拆成两个,然后离线下来,扫描线。

代码

#include<bits/stdc++.h>
#define go(x) for(int i=head[x];i;i=edge[i].nxt)
#define now edge[i].v
using namespace std;
typedef long long ll;
const int sz=3e5+7;
int n,T;
ll Ans;
int t,m,tot;
int u,v,cnt;
int ans[sz];
int head[sz];
int a[sz];
int f[sz];
int st[sz],ed[sz];//子树内dfn的起点和终点
int siz[sz],mx[sz],cl[sz],son[sz];//子树大小,最大子树,次大子树,重儿子
struct Que{
int id,tp,rl;
const bool operator <(Que const & p)const{
return rl<p.rl;
}
}q[sz<<1];
struct Edge{
int v,nxt;
}edge[sz<<1];
void make_edge(int u,int v){
edge[++cnt]=(Edge){v,head[u]};head[u]=cnt;
edge[++cnt]=(Edge){u,head[v]};head[v]=cnt;
}
bool cmp(int x,int y){
return siz[x]<siz[y];
}
void add(int x,int sum){
for(;x<=n;x+=x&-x) f[x]+=sum;
}
int query(int x){
int ret=0;
for(;x;x-=x&-x) ret+=f[x];
return ret;
}
int Query(int l,int r){
int ret=0;
if(l>n||r<1) return 0;
int R=min(r,n),L=max(l,1);
ret=query(R)-query(L-1);
return ret;
}
void dfs(int x,int fa){
st[x]=++t;
siz[x]=1;
mx[x]=cl[x]=son[x]=0;
go(x) if(now!=fa){
dfs(now,x);
siz[x]+=siz[now];
if(siz[now]>mx[x]) cl[x]=mx[x],mx[x]=siz[now],son[x]=now;
else if(siz[now]>cl[x]) cl[x]=siz[now];
}
ed[x]=t;
}
void Dfs(int x,int fa){
ans[x]-=Query(n-2*siz[x],n-2*mx[x]);
if(x^1) add(siz[x],1);
ans[x]+=Query(2*mx[x],2*siz[x]);
go(x) if(now!=fa) Dfs(now,x);
if(x^1) add(siz[x],-1);
}
void work(){
scanf("%d",&n);
cnt=t=0;
for(int i=1;i<=n;i++) head[i]=ans[i]=f[i]=0;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
make_edge(u,v);
}
dfs(1,0);
Dfs(1,0);
for(int i=1;i<n;i++) a[i]=i+1;
sort(a+1,a+n,cmp); m=0;
for(int i=1;i<=n;i++){
q[++m]=(Que){i,-1,n-2*siz[i]-1};
q[++m]=(Que){i,1,n-2*mx[i]};
}
sort(q+1,q+m+1);
tot=1;
for(int i=1;i<=n;i++) f[i]=0;
for(int i=1;i<=m;i++){
while(tot<n&&siz[a[tot]]<=q[i].rl){
add(st[a[tot]],1);
tot++;
}
int x=q[i].id;
ans[x]+=(Query(1,n)-Query(st[x],ed[x]))*q[i].tp;
} m=0;
for(int i=1;i<=n;i++)
q[++m]=(Que){i,1,min(2*siz[i]-n,n-2*mx[i])};
sort(q+1,q+m+1);
tot=1;
for(int i=1;i<=n;i++) f[i]=0;
for(int i=1;i<=m;i++){
while(tot<n&&siz[a[tot]]<=q[i].rl){
add(st[a[tot]],1);
tot++;
}
int x=q[i].id;
ans[x]+=(Query(st[x],ed[x])-Query(st[son[x]],ed[son[x]])-Query(st[x],st[x]))*q[i].tp;
} m=0;
for(int i=1;i<=n;i++){
if(2*mx[i]-n>min(2*siz[i]-n,n-2*cl[i])) continue;
q[++m]=(Que){i,-1,2*mx[i]-n-1};
q[++m]=(Que){i,1,min(2*siz[i]-n,n-2*cl[i])};
}
sort(q+1,q+m+1);
tot=1;
for(int i=1;i<=n;i++) f[i]=0;
for(int i=1;i<=m;i++){
while(tot<n&&siz[a[tot]]<=q[i].rl){
add(st[a[tot]],1);
tot++;
}
int x=q[i].id;
ans[x]+=Query(st[son[x]],ed[son[x]])*q[i].tp;
}
Ans=0;
for(int i=1;i<=n;i++) Ans+=1ll*i*ans[i];
printf("%lld\n",Ans);
}
int main(){
scanf("%d",&T);
while(T--) work();
}

CSP-S 2019 Day 2 T3 树的重心的更多相关文章

  1. @CSP模拟2019.10.16 - T3@ 垃圾分类

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 为了保护环境,p6pou建设了一个垃圾分类器. 垃圾分类器是一个 ...

  2. 上午小测3 T1 括号序列 && luogu P5658 [CSP/S 2019 D1T2] 括号树 题解

    前 言: 一直很想写这道括号树..毕竟是在去年折磨了我4个小时的题.... 上午小测3 T1 括号序列 前言: 原来这题是个dp啊...这几天出了好几道dp,我都没看出来,我竟然折磨菜. 考试的时候先 ...

  3. 【CSP-S 2019】树的重心(重心的性质)

    Description 给定一颗 \(n\) 个顶点的树 \(\text T\),共 \(n-1\) 次断边操作,每次将树分为两部分 \(\text T_1, \text T_2\),求: \[\su ...

  4. 【CSP-S 2019】【洛谷P5666】树的重心【主席树】【树状数组】【dfs】

    题目: 题目链接:https://www.luogu.com.cn/problem/P5666 小简单正在学习离散数学,今天的内容是图论基础,在课上他做了如下两条笔记: 一个大小为 \(n\) 的树由 ...

  5. 【CSP模拟赛】仔细的检查(树的重心&树hash)

    题目描述 nodgd家里种了一棵树,有一天nodgd比较无聊,就把这棵树画在了一张纸上.另一天nodgd更无聊,就又画了一张.  这时nodgd发现,两次画的顺序是不一样的,这就导致了原本的某一个节点 ...

  6. [CSP-S2019]树的重心 题解

    CSP-S2 2019 D2T3 考场上扔了T2来打这题的部分分,然后没看到数据范围是等号,不知道怎么判完全二叉树然后40分滚粗…… ---- 思路分析 很容易想到$O(n^2)$每次暴力找重心,这个 ...

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

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

  8. poj1655 树的重心 树形dp

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

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

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

随机推荐

  1. Linux QtCreator 创建工程

    这一天天的,都快成废物了, 每天忙得要死, 各种乱七八糟杂事,连点学习的时间都没有了, 这才一年不碰Linux,创建工程都不会了, Ubuntu 1N.N.N + QtCreator 创建工程 不安装 ...

  2. opencv编译:opencv 3.4.1 编译 contrib模块,增加人脸识别

    start cmake-gui select the opencv source code folder and the folder where binaries will be built (th ...

  3. 【默默努力】PixelFire

    先放下我玩游戏的效果图: 关于游戏最后的结束部分其实我还没有截图,看着挺好看的,后面的效果 再放作者大大的项目地址:https://github.com/panruiplay/PixelFire 接下 ...

  4. 「题解」NOIP模拟测试题解乱写II(36)

    毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...

  5. 当EntityFramework爱上AutoMapper

    有时候相识即是一种缘分,相爱也不需要太多的理由,一个眼神足矣,当EntityFramework遇上AutoMapper,就是如此,恋爱虽易,相处不易. 在DDD(领域驱动设计)中,使用AutoMapp ...

  6. Python学习day40-并发编程(终)

    figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...

  7. 我学习python没有记住的东西

    格式化 # 格式化 a=123 b='ww' print("%d,%s,%%"%(a,b)) # %d,%s,%f,%c,%f 格式化代码:print('{}{}'.format( ...

  8. Appscan standard怎么设置外部浏览器为IE

    Appscan standard怎么设置外部浏览器为IE   方法/步骤     首先,打开一个的Appscan 的界面中,点击菜单中的 工具 的选项   点击了工具的选项之后,弹出了下拉菜单选中为 ...

  9. 《数据结构与算法分析——C语言描述》ADT实现(NO.04) : AVL树(AVL-Tree)

    上次我们已经实现了普通的二叉查找树.利用二叉查找树,可以用O(logN)高度的树状结构存储和查找数据,提高了存储和查找的效率. 然而,考虑一种极端情形:依次插入1,2,3,4,5,6,7,8,9九个元 ...

  10. Activiti 接收任务活动

    流程中往往需要特定人接受任务并进行一定操作才能继续进行下去. 代码如下 import java.io.InputStream; import org.activiti.engine.ProcessEn ...