题面

给你一棵

n

n

n 个结点的树,对于所有的

k

[

0

,

n

]

k\in[0,n]

k∈[0,n] ,求出

M

E

X

=

k

{\rm MEX}=k

MEX=k 的路径数量。

一条路径的

M

E

X

\rm MEX

MEX 定义为该路径上没出现的最小结点编号(编号从

0

0

0 到

n

1

n-1

n−1)。

1

n

2

e

5

1\leq n\leq 2e5

1≤n≤2e5,多组数据。

题解

一条路径的

M

E

X

\rm MEX

MEX 恰好等于

k

k

k 的充要条件是

  • 结点

    0

    0

    0 到

    k

    1

    k-1

    k−1 都出现在路径上。

  • 结点

    k

    k

    k 没有出现在路径上。

我们先想想怎么求

0

0

0 到

i

i

i 都出现在路径上的路径个数,令其为

f

(

i

)

f(i)

f(i)。

如果这

i

+

1

i+1

i+1 个点在树上没办法由一条路径经过(形成的虚树不是一条链)那么答案一定为 0,并且

f

(

i

+

1

)

f(i+1)

f(i+1) 直到

f

(

n

)

f(n)

f(n) 的值也都是 0 。在这之前,如果包含它们的最短路径两端是

A

A

A 和

B

B

B(不妨令它们没有祖先关系),那么

f

(

i

)

f(i)

f(i) 就为

A

A

A 端子树大小 ×

B

B

B 端子树大小。

M

E

X

\rm MEX

MEX 等于

k

k

k 的答案不难发现可以用一个小容斥算出:

f

(

k

1

)

f

(

k

)

f(k-1)-f(k)

f(k−1)−f(k) 。

然后,难点就剩计算

f

(

i

)

f(i)

f(i) 了。首先不妨令

f

(

1

)

=

n

(

n

1

)

2

f(-1)=\cfrac{n*(n-1)}{2}

f(−1)=2n∗(n−1)​

接着我们发现,如果把 0 当作根的话,一切都变得明朗。从

0

0

0 到

i

i

i 形成的虚树一定都经过根,那么我们用

A

A

A 和

B

B

B 两个变量存路径的两端就足够了(初始为 0)。从小到大依次加入点,如果出现加入的点

x

x

x 分别与

A

A

A

B

B

B 的最近公共祖先不是

1

,

A

,

B

,

x

1,A,B,x

1,A,B,x 中任何一个的话,那当前的

f

(

i

)

f(i)

f(i) 以及后面的都是 0 了,就不用继续算了。否则的话,就讨论讨论,看怎么更新

A

A

A 和

B

B

B 。

计算

f

(

i

)

f(i)

f(i) 的时候,如果

A

A

A 和

B

B

B 都是 0,那么就是经过 0 的路径数,提前处理一下即可;如果

A

A

A 和

B

B

B 其中一个是 0(假设是

A

A

A),那么先求出

B

B

B 往上走刚好走到 0 的儿子的那个点

B

B'

B′,答案就是

(

n

s

i

z

[

B

]

)

×

s

i

z

[

B

]

(n-siz[B'])\times siz[B]

(n−siz[B′])×siz[B];如果

A

A

A 和

B

B

B 都大于 0 的话,答案自然是

s

i

z

[

A

]

×

s

i

z

[

B

]

siz[A]\times siz[B]

siz[A]×siz[B]。

具体实现有点细节多。复杂度

O

(

n

log

n

)

O(n\log n)

O(nlogn)。

CODE

#include<cstdio>
#include<vector>
#include<cmath>
#include<map>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 300005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) ((-x) & (x))
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
int n,m,i,j,s,o,k;
LL as[MAXN];
vector<int> g[MAXN];
int d[MAXN],dfn[MAXN],rr[MAXN],tim,siz[MAXN];
LL dp[MAXN];
int A,B,FLAG,f[MAXN][21];//18
void dfs(int x,int ff) {
d[x] = d[f[x][0] = ff] + 1;dp[x] = 0;siz[x] = 1;
dfn[x] = ++ tim;
for(int i = 1;i <= 18;i ++) f[x][i] = f[f[x][i-1]][i-1];
for(int i = 0;i < (int)g[x].size();i ++) {
int y = g[x][i];
if(y != ff) {
dfs(y,x);
dp[x] += siz[x] *1ll* siz[y];
siz[x] += siz[y];
}
}rr[x] = tim;
return ;
}
int lca(int a,int b) {
if(d[a] < d[b]) swap(a,b);
if(d[a] > d[b]) {
for(int i = 18;i >= 0;i --) {
if(d[f[a][i]] >= d[b]) a = f[a][i];
}
}if(a == b) return a;
for(int i = 18;i >= 0;i --) {
if(f[a][i] != f[b][i]) {
a = f[a][i]; b = f[b][i];
}
}return f[a][0];
}
LL cal() {
if(!FLAG) return 0;
if(A > B) swap(A,B);
if(A == 1 && B == 1) return dp[1];
if(A == 1) {
int ft = B;
for(int i = 18;i >= 0;i --) {
if(d[f[ft][i]] > d[A]) ft = f[ft][i];
}
int nm1 = n - (rr[ft]-dfn[ft]+1);
return (rr[B]-dfn[B]+1) *1ll* nm1;
}
return (rr[B]-dfn[B]+1) *1ll* (rr[A]-dfn[A]+1);
}
void addp(int x) {
if(!FLAG) return ;
if(A > B) swap(A,B);
if(A == 1 && B == 1) B = x;
else if(A == 1) {
int lc = lca(x,B);
if(lc == 1) A = x;
else if(lc == B) B = x;
else if(lc != x) FLAG = 0;
}
else {
int lc1 = lca(A,x),lc2 = lca(B,x);
if(lc1 == A) A = x;
else if(lc2 == B) B = x;
else if((lc1 == x) || (lc2 == x)) return ;
else FLAG = 0;
}return ;
}
int main() {
int T = read();
while(T --) {
n = read();
tim = 0;A = B = FLAG = 1;
for(int i = 1;i <= n+1;i ++) {
g[i].clear(); as[i] = 0;
memset(f[i],0,sizeof(f[i]));
}
for(int i = 1;i < n;i ++) {
s = read()+1;o = read()+1;
g[s].push_back(o);
g[o].push_back(s);
}
dfs(1,0);
as[1] = n*1ll*(n-1)/2ll;
for(int i = 2;i <= n;i ++) {
LL ass = cal();
as[i-1] -= ass;
as[i] = ass;
addp(i);
}
LL ass = cal();
as[n] -= ass; as[n+1] = ass;
for(int i = 1;i <= n+1;i ++) {
printf("%lld ",as[i]);
}ENDL;
}
return 0;
}

[CF1527D] MEX Tree (lca)的更多相关文章

  1. 面试题6:二叉树最近公共节点(LCA)《leetcode236》

    Lowest Common Ancestor of a Binary Tree(二叉树的最近公共父亲节点) Given a binary tree, find the lowest common an ...

  2. 洛谷P3379 【模板】最近公共祖先(LCA)

    P3379 [模板]最近公共祖先(LCA) 152通过 532提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 为什么还是超时.... 倍增怎么70!!题解好像有 ...

  3. Device Tree(三):代码分析【转】

    转自:http://www.wowotech.net/linux_kenrel/dt-code-analysis.html Device Tree(三):代码分析 作者:linuxer 发布于:201 ...

  4. 图论--最近公共祖先问题(LCA)模板

    最近公共祖先问题(LCA)是求一颗树上的某两点距离他们最近的公共祖先节点,由于树的特性,树上两点之间路径是唯一的,所以对于很多处理关于树的路径问题的时候为了得知树两点的间的路径,LCA是几乎最有效的解 ...

  5. P3379 【模板】最近公共祖先(LCA)

    P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...

  6. 洛谷P3379 【模板】最近公共祖先(LCA)(dfs序+倍增)

    P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...

  7. 「LuoguP3379」 【模板】最近公共祖先(LCA)

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  8. 洛谷——P3379 【模板】最近公共祖先(LCA)

    P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...

  9. luogo p3379 【模板】最近公共祖先(LCA)

    [模板]最近公共祖先(LCA) 题意 给一个树,然后多次询问(a,b)的LCA 模板(主要参考一些大佬的模板) #include<bits/stdc++.h> //自己的2点:树的邻接链表 ...

随机推荐

  1. Docker容器手动安装oracle19C

    Docker容器手动安装oracle19C docker容器体积小,与宿主机共用内核参数,因此修改宿主机的内核参数即是修改容器的内核参数 1.修改宿主机内核参数 [root@localhost ~]# ...

  2. 2 万字 + 20张图| 细说 Redis 九种数据类型和应用场景

    作者:小林coding 计算机八股文网(操作系统.计算机网络.计算机组成.MySQL.Redis):https://xiaolincoding.com 大家好,我是小林. 我们都知道 Redis 提供 ...

  3. Xilinx DMA的几种方式与架构

    DMA是direct memory access,在FPGA系统中,常用的几种DMA需求: 1. 在PL内部无PS(CPU这里统一称为PS)持续干预搬移数据,常见的接口形态为AXIS与AXI,AXI与 ...

  4. 如何使用lerna进行多包(package)管理

    为什么要用lerna 将大型代码仓库分割成多个独立版本化的 软件包(package)对于代码共享来说非常有用.但是,如果某些更改 跨越了多个代码仓库的话将变得很 麻烦 并且难以跟踪,并且, 跨越多个代 ...

  5. 关于个人全栈项目【臻美IT】博客类出现的问题以及解决方法

    每做一个项目,要记得写下心得哦,别偷懒啊!先上网址:https://www.maomin.club/ 这个项目属于博客类的,因为百度审核的问题就大体做了下,就当来练练手,里面文章链接的是CSDN的博客 ...

  6. sql-自动增长的列

    mysql自动增长 如果某一列是数值类型的,使用 auto_increment 可以来完成值得自动增长 方式1:创建表时,添加主键约束,并且完成主键自增长 create table stu( id i ...

  7. Lydon 分解与最小表示法

    我们定义一个串是 \(\text{Lyndon}\) 串,当且仅当这个串的最小后缀就是这个串本身. 该命题等价于这个串是它的所有循环表示中字典序最小的. 引理 1:如果 \(u\) 和 \(v\) 都 ...

  8. ArrayList集合存储基本数据类型

    如何存储基本数据类型 ArrayList对象不能存储基本类型,只能存储引用类型的数据.类似 <int> 不能写,但是存储基本数据类型对应的 包装类型是可以的.所以,想要存储基本类型数据, ...

  9. 简单状压dp的思考 - 最大独立集问题和最大团问题 - 贰

    接着上文 题目链接:最大独立集问题 上次说到,一种用状压DP解决任意无向图最大团问题(MCP)的方程是: 注:此处popcountmax代表按照二进制位下1的个数作为关键字比较,即选择二进制位下1的个 ...

  10. APISpace 空号检测API接口 免费好用

    空号检测也称空号在线过滤,在线筛号,号码在线清洗.空号检测平台借助第五代大数据空号检测系统,为用户提供高精准的空号检测.号码过滤.号码筛选.号码清洗等众多号码检测功能,让用户快速准确的检测出活跃号.空 ...