D. MEX Tree(容斥+双指针)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D. MEX Tree(容斥+双指针)相关的知识,希望对你有一定的参考价值。

D. MEX Tree(容斥+双指针)

a n s i ans_i ansi为异或值为 i i i的路径数。

f i f_i fi为异或值 ≥ i \\ge i i的路径数。

g i g_i gi为异或值 > i >i >i​的路径数。

s z i sz_i szi表示结点 i i i的子树大小。

容易发现: g i = f i + 1 g_i=f_i+1 gi=fi+1

考虑用容斥计算 a n s i = f i − g i ans_i=f_i-g_i ansi=figi

如果我们能计算出 g i , i ∈ [ 1 , n ] g_i,i\\in [1,n] gi,i[1,n] 我们就可以递推得到 a n s i ans_i ansi​。

f 0 f_0 f0 就是整棵树的路径数, a n s 0 ans_0 ans0 所有 0 0 0的儿子子树内的路径数之和。

f 0 = n ( n − 1 ) 2 , a n s 0 = ∑ v ∈ s o n 0 s z v ( s z v − 1 ) 2 \\large f_0=\\dfracn(n-1)2,ans_0=\\sum\\limits_v\\in son_0\\dfracsz_v(sz_v-1)2 f0=2n(n1),ans0=vson02szv(szv1)

g 0 = f 0 − a n s 0 = f 1 g_0=f_0-ans_0=f_1 g0=f0ans0=f1

所以接下来的关键就是求 g i , ∈ [ 1 , n ] g_i, \\in [1,n] gi,[1,n]

考虑用双指针。

用两个指针 l , r l,r l,r​ 分别表示 g i g_i gi​ 对应的链的端点。

则答案就是: s z l × s z r sz_l\\times sz_r szl×szr

显然这条链包含 0 , 1 , 2 , … , i 0,1,2,\\dots ,i 0,1,2,,i 结点,且 i = l i=l i=l i = r i=r i=r

我们考虑这条链如何扩展到 g i g_i gi

显然要满足 g i g_i gi​​​必须满足 g i − 1 g_i-1 gi1​​​,所以 g i g_i gi​​​ 必须在 p a t h ( l , r ) path(l,r) path(l,r)​​​这条路径上扩展,也就是说 i i i​​​ 往上走必须走到 l l l​​​或者 r r r​​​。

如果 i i i​走步到 l l l​或者 r r r​,说明无解 g i = 0 g_i=0 gi=0,则 a n s j = 0 , ( j   > i ) ans_j=0,(j\\ >i) ansj=0,(j >i)直接 b r e a k break break

否则更新 p a t h ( l , r ) path(l,r) path(l,r)

需要注意的是如果 l = 0 l=0 l=0​或者 r = 0 r=0 r=0​,计算贡献时要 s z 0 sz_0 sz0​减掉对应的那颗子树,注意是永久性修改,因为链是继承关系。

时间复杂度: O ( n ) O(n) O(n)

#include<bits/stdc++.h>
#define ll long long
const int N = 2e5+10;
int t,n,fa[N],cov[N];
ll sz[N],ans[N],fl,p,q;
std::vector<int> g[N];
void dfs(int x,int f)
	fa[x] = f ;
	sz[x] = 1 ; 
	for(auto p:g[x])
		if(p==f) continue;
		dfs(p,x);
		sz[x]+=sz[p];
	

void add(int x)
	if(cov[x]) return ;
	if(!cov[fa[x]]) add(fa[x]); 
	cov[x] = 1;
	if(fa[x]!=q&&fa[x]!=p)
		fl = 0 ;
		return ;
	
	else
		 if(fa[x]==p) p=x;
		 else q=x;
		 if(fa[x]==0) sz[0]-=sz[x];
	

int main()
	scanf("%d",&t);
	while(t--)
		scanf("%d",&n);
		for(int i=0;i<=n;++i) g[i].clear(),ans[i]=0,cov[i]=0;
		for(int i=1;i<=n-1;++i)
			int u,v;
			scanf("%d%d",&u,&v);
			g[u].push_back(v);
			g[v].push_back(u)

以上是关于D. MEX Tree(容斥+双指针)的主要内容,如果未能解决你的问题,请参考以下文章

CF1527D MEX Tree(mex&树&容斥)

CF1527D MEX Tree(mex&树&容斥)

点分治

[POJ 1741] Tree

D. Numbers on Tree

bzoj 3365: [Usaco2004 Feb]Distance Statistics 路程统计容斥原理+点分治