[CF1527D] MEX Tree (lca)
题面
给你一棵
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)的更多相关文章
- 面试题6:二叉树最近公共节点(LCA)《leetcode236》
Lowest Common Ancestor of a Binary Tree(二叉树的最近公共父亲节点) Given a binary tree, find the lowest common an ...
- 洛谷P3379 【模板】最近公共祖先(LCA)
P3379 [模板]最近公共祖先(LCA) 152通过 532提交 题目提供者HansBug 标签 难度普及+/提高 提交 讨论 题解 最新讨论 为什么还是超时.... 倍增怎么70!!题解好像有 ...
- Device Tree(三):代码分析【转】
转自:http://www.wowotech.net/linux_kenrel/dt-code-analysis.html Device Tree(三):代码分析 作者:linuxer 发布于:201 ...
- 图论--最近公共祖先问题(LCA)模板
最近公共祖先问题(LCA)是求一颗树上的某两点距离他们最近的公共祖先节点,由于树的特性,树上两点之间路径是唯一的,所以对于很多处理关于树的路径问题的时候为了得知树两点的间的路径,LCA是几乎最有效的解 ...
- P3379 【模板】最近公共祖先(LCA)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- 洛谷P3379 【模板】最近公共祖先(LCA)(dfs序+倍增)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- 「LuoguP3379」 【模板】最近公共祖先(LCA)
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 洛谷——P3379 【模板】最近公共祖先(LCA)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- luogo p3379 【模板】最近公共祖先(LCA)
[模板]最近公共祖先(LCA) 题意 给一个树,然后多次询问(a,b)的LCA 模板(主要参考一些大佬的模板) #include<bits/stdc++.h> //自己的2点:树的邻接链表 ...
随机推荐
- 技术分享 | app测试中常用的Android模拟器
原文链接 Emulator Emualor 是 Android Studio 自带的模拟器,是官方提供的工具,Android 开发最常使用的就是这一款. 它功能非常齐全,电话本.通话等功能都可正常使用 ...
- Python中的逻辑表达式
首先要明确一点,Python的逻辑运算符,可以用来操作任何类型的表达式(不局限于Bool类型),且运算后的结果也不一定是Bool类型的,而是其左右其中一个表达式的值 表达式1 and 表达式2 pyt ...
- Linux shell 2>&1的意思
在脚本里经常看到 ./xxx.sh > /dev/null 2>&1 ./xxx.sh > log.file 2>&1 在shell中输入输出都有对应的文件描述 ...
- 实现领域驱动设计 - 使用ABP框架 - 创建实体
用例演示 - 创建实体 本节将演示一些示例用例并讨论可选场景. 创建实体 从实体/聚合根类创建对象是实体生命周期的第一步.聚合/聚合根规则和最佳实践部分建议为Entity类创建一个主构造函数,以保证创 ...
- SAP 时区转换
DATA:l_tzone TYPE tzonref-tzone. "TIME ZONE DATA:l_timesp TYPE tzonref-tstamps."TIME ...
- 如何将 DevSecOps 引入企业?
前 言 现如今,大部分企业已经在内部实现了 DevOps 实践.DevOps 为团队提供了交付可靠软件和快速更新的方法论.这种方法让团队更专注于质量而不是将时间浪费在运维上.然而,结果是,安全实践往往 ...
- resultMap自定义映射(多对一)
自定义resultMap,处理复杂的表关系,实现高级结果集映射 1) id :用于完成主键值的映射 2) result :用于完成普通列的映射 3) association :一个复杂的类型关联;许多 ...
- Lambda表达式有参数有返回值的练习(自定义接口)和Lambda省略格式&Lambda使用前提
给定一个计算器Calculator接口,内含抽象方法calc可以将两个int数字相加得到和值 使用L ambdo的标准格式调用invokeCalc方法,完成120和130的相加计算 public in ...
- 题解 P2278 【[HNOI2003]操作系统】
一道大模拟 题面想必大家都很清楚了,一堆进程在抢占资源,除了先来后到的顺序以外,优先级大的还可以插队,空闲的时候未结束的进程会插进来占用空闲的时间. 那么,我们可以容易地想到,我们寻找这个最大的优先级 ...
- Restarting network (via systemctl): Job for network.service failed because the control process exited with error code. See "systemctl status network.service" and "journalctl -xe" for details.
编辑完 ip地址,要重启网络 sudo service network restart 结果返回错误,错误如下 Restarting network (via systemctl): Job for ...