CF1527D MEX Tree
MEX Tree – Luogu | New Ecosystem of Computer Science Education (luogu.com.cn)
Article directory
- CF1527D MEX Tree
-
- The general idea of the topic
- The basic idea
- ask
- Revise
- code
The main idea of the title
give one
n
n
A tree of n points, starting from
0
0
0 to
n
?
1
n-1
n?1 number. The weight that defines a path is the number of all points on the path
m
e
x
mex
mex. for each
0
≤
i
≤
n
0\le i\le n
0≤i≤n find
m
e
x
mex
mex for
i
i
There are several paths to i. Note that the paths counted here need to include at least one edge.
a collection of
m
e
x
mex
mex is defined as the smallest non-negative integer not in the set.
Basic idea
It is observed that we are dealing with
i
i
When i,
0
→
i
?
1
0\to i – 1
0→i?1 must be on a path, otherwise all subsequent answers will be
0
0
0
s
z
i
sz_i
szi? means
i
i
i is the size of the subtree of the root
s
p
sp
sp means not
0
0
0 endpoint is located for
0
0
The corresponding subtree size of 0
The doubling requirement will be used below
l
c
a
lca
lca
We can do something similar to virtual tree operation.
Here it is assumed that
0
0
0 is the root
Ask
So the query can be divided into
3
3
3 situations:
-
i
i
i is in the current path
-
i
i
i is a descendant of the current path endpoint
-
i
i
i does not belong to the above situation
Then
m
e
x
=
0
mex = 0
mex=0 and
m
e
x
=
1
mex = 1
mex=1 is a special treatment
when
m
e
x
=
0
mex = 0
When mex=0:
As long as you don’t pass by
0
0
0 paths all meet the conditions
So the answer is
0
0
Select any path between two points in all subtrees of 0
when
m
e
x
=
1
mex = 1
When mex=1:
exist
n
n
Number of options for selecting any two points among n points
?
–
?
m
e
x
=
0
mex = 0
Number of solutions with mex=0
LL gs (LL x) {<!-- --> return x * (x - 1) / 2; } void pre_ans () {<!-- --> ans[1] = gs (sz[0] - sz[1]); int y; for (int i = hd[0] ; i ; i = e[i].nt) {<!-- --> y = e[i].to; ans[0] + = gs (sz[y]); int lca = Lca (y , 1); if (lca == y) ans[1] -= gs (sz[y] - sz[1]); else ans[1] -= gs (sz[y]); } }
Now we divide other inquiries into two situations
Neither endpoint nor
0
0
0, the two endpoints are
x
,
y
x , y
x, y
-
i
i
i on the path $lca(x , i) =i \or lca (y , i) = i $
The answer is
0
0
0
-
i
i
i is a descendant of the current path endpoint KaTeX parse error: Undefined control sequence: \or at position 17: …ca (x , i) = x \?o?r? ?lca (y , i) = y
The answer is that for the endpoint subtree size
?
–
?
s
z
i
sz_i
szi? multiplied by the other terminal tree size
-
Otherwise, the answer is
s
z
x
?
s
z
y
sz_x*sz_y
szxszy?
There is a point for
0
0
In the case of 0, the other endpoint is
x
x
x
-
i
i
i is in the current path
l
c
a
(
x
,
i
)
=
i
lca (x , i) = i
lca(x,i)=i
The answer is
0
0
0
-
i
i
i is a descendant of the current path endpoint
i
i
i is a descendant of the endpoint that is not zero
l
c
a
(
x
,
i
)
=
x
lca (x , i) = x
lca(x,i)=x, then the answer is:
(
s
i
z
[
x
]
?
s
i
z
[
i
]
)
?
(
s
i
z
[
0
]
?
s
p
)
(siz[x] – siz[i]) * (siz[0] – sp)
(siz[x]?siz[i])?(siz[0]?sp)
i
i
i is
0
0
0 descendants
l
c
a
(
x
,
i
)
=
0
lca (x , i) = 0
lca(x,i)=0, then the answer is:
(
s
i
z
[
0
]
?
s
p
?
s
i
z
[
i
]
)
?
s
i
z
[
x
]
(siz[0] – sp – siz[i]) * siz[x]
(siz[0]?sp?siz[i])?siz[x]
-
i
i
i does not belong to any of the above situations
So
i
i
i is the fork of the current path, then the answer is:
(
s
i
z
[
0
]
?
s
p
)
?
s
i
z
[
x
]
(siz[0] – sp) * siz[x]
(siz[0]?sp)?siz[x]
LL gt_ans (int x) {<!-- --> int lca1 = Lca (x , l) , lca2 = Lca (x , r); LL ans1, ans2; if (r) {<!-- --> ans1 = sz[l] , ans2 = sz[r]; if (lca1 == x || lca2 == x) return 0; else if (lca1 == l) ans1 -= sz[x]; else if (lca2 == r) ans2 -= sz[x]; } else {<!-- --> ans1 = sz[l] , ans2 = sz[r] - sp; if (lca1 == x || lca2 == x) return 0; else if (lca1 == l) ans1 -= sz[x]; else if (lca1 == 0) ans2 -= sz[x]; } return ans1 * ans2; }
Modify
try to
i
i
i is added to the current path
1. Neither of the two ends
0
0
0
-
i
i
i is already on the path KaTeX parse error: Undefined control sequence: \or at position 17: …ca (x , i) = i \?o?r? ?lca (y , i) = i
Don’t worry about it
-
i
i
i is a descendant of one end $lca(x, i) = x \or lca (y, i) = y $
Just set that endpoint to
i
i
i would be fine
-
If it does not fall into the above two situations
Then it is a bifurcation, and the answers directly below are all
0
0
0 would be fine
2. At least one end is
0
0
0 case
-
If both ends are
0
0
0
Directly set one end to
i
i
i
-
i
i
i is already on the path
l
c
a
(
x
,
i
)
=
i
lca (x , i) = i
lca(x,i)=i
Never mind
-
l
c
a
(
x
,
i
)
=
x
lca (x , i) = x
lca(x,i)=x
x
=
i
x = i
x=i
-
Does not belong to the above situation
1. bifurcation
l
c
a
(
x
,
i
)
≠
0
lca (x , i)\
eq 0lca(x,i)=0 insertion failed
2,
x
≠
0
x \
eq 0x=0 and
l
c
a
(
x
,
i
)
=
0
lca (x , i) = 0
lca(x,i)=0, then
y
=
i
y = i
y=i
bool add (int x) {<!-- --> int lca1 = Lca (l , x) , lca2 = Lca (r , x); if (r) {<!-- --> if (lca1 == l) {<!-- --> l = x; return 1; } else if (lca1 == x) return 1; if (lca2 == r) {<!-- --> r = x; return 1; } else if (lca2 == x) return 1; } else {<!-- --> if (lca1 & amp; & amp; (lca1 != l & amp; & amp; lca1 != x)) return 0; else if (lca1 == l ) {<!-- --> l = x; return 1; } else if (lca1 == x) return 1; else if (lca1) return 0; else {<!-- --> r = x; return 1; } } return 0; }
code
#include#define fu(x , y , z) for(int x = y ; x <= z ; x + + ) #define fd(x, y, z) for(int x = y; x >= z; x --) #define LL long long using namespace std; const int N = 6e5 + 5 , inf = 2e5; int n , sz[N] , hd[N] , cnt , fa[N] , sp , dep[N] , f[N << 1][30] , l , r; LL tw[30] , ans[N] , lg2[inf + 5]; struct E { int to, nt; } e[N << 1]; void add (int x , int y) { e[ + + cnt].to = y , e[cnt].nt = hd[x] , hd[x] = cnt; } int Lca (int x , int y) { int flg; while (dep[x] != dep[y]) { flg = 0; if (dep[x] > dep[y]) swap (x , y); fd (i, 25, 0) { while (dep[f[y][i]] > dep[x]) { y = f[y][i]; flg = 1; } } if (!flg) break; } while (dep[x] != dep[y]) { if (dep[x] > dep[y]) swap (x , y); y = f[y][0]; } while (x != y) { flg = 0; fd (i, 25, 0) { while (f[x][i] != f[y][i]) { x = f[x][i] , y = f[y][i]; flg = 1; } } if (!flg) break; } while (x != y) x = f[x][0] , y = f[y][0]; return x; } void dfs1 (int x) { int y; sz[x] = 1; for (int i = hd[x] ; i ; i = e[i].nt) { y = e[i].to; if (fa[x] == y) continue; fa[y] = x; dep[y] = dep[x] + 1; dfs1(y); sz[x] + = sz[y]; } } void gt_f () { fu (i , 0 , n - 1) fu (j , 1 , 25) f[i][j] = 0; dep[0] = 1; dfs1(0); fu (i , 0 , n - 1) f[i][0] = fa[i]; fu (j , 1 , 25) { fu (i , 0 , n - 1) { f[i][j] = f[f[i][j - 1]][j - 1]; } } } LL gs (LL x) {<!-- --> return x * (x - 1) / 2; } void pre_ans () {<!-- --> ans[1] = gs (sz[0] - sz[1]); int y; for (int i = hd[0] ; i ; i = e[i].nt) {<!-- --> y = e[i].to; ans[0] + = gs (sz[y]); int lca = Lca (y , 1); if (lca == y) ans[1] -= gs (sz[y] - sz[1]); else ans[1] -= gs (sz[y]); } } bool add (int x) {<!-- --> int lca1 = Lca (l , x) , lca2 = Lca (r , x); if (r) {<!-- --> if (lca1 == l) {<!-- --> l = x; return 1; } else if (lca1 == x) return 1; if (lca2 == r) {<!-- --> r = x; return 1; } else if (lca2 == x) return 1; } else {<!-- --> if (lca1 & amp; & amp; (lca1 != l & amp; & amp; lca1 != x)) return 0; else if (lca1 == l ) {<!-- --> l = x; return 1; } else if (lca1 == x) return 1; else if (lca1) return 0; else {<!-- --> r = x; return 1; } } return 0; } LL gt_ans (int x) {<!-- --> int lca1 = Lca (x , l) , lca2 = Lca (x , r); LL ans1, ans2; if (r) {<!-- --> ans1 = sz[l] , ans2 = sz[r]; if (lca1 == x || lca2 == x) return 0; else if (lca1 == l) ans1 -= sz[x]; else if (lca2 == r) ans2 -= sz[x]; } else {<!-- --> ans1 = sz[l] , ans2 = sz[r] - sp; if (lca1 == x || lca2 == x) return 0; else if (lca1 == l) ans1 -= sz[x]; else if (lca1 == 0) ans2 -= sz[x]; } return ans1 * ans2; } int main () { tw[0] = 1ll; fu (i , 1 , 25) tw[i] = 1ll * tw[i - 1] * 2; int T , u , v; scanf ("%d" , & amp;T); while (T --) { scanf ("%d" , & amp;n); cnt = 0; fu (i , 0 , n) ans[i] = hd[i] = fa[i] = 0; fu(i, 0, n) fu (j , 0 , 25) f[i][j] = -1; fu (i , 1 , n - 1) { scanf ("%d%d" , & amp;u , & amp;v); add (u , v) , add (v , u); } gt_f (); pre_ans (); for (int i = hd[0] ; i ; i = e[i].nt) { if (Lca (e[i].to , 1) == e[i].to) { sp = sz[e[i].to]; break; } } l = r = 0; fu (i , 2 , n) { if (!add (i - 1)) break; if (i == n) { ans[i] = 1; break; } ans[i] = gt_ans (i); } fu(i, 0, n) printf ("%lld " , ans[i]); printf ("\ "); } return 0; }