2021牛客暑期多校训练营7 F.xay loves trees(主席树+树上尺取)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营7 F.xay loves trees(主席树+树上尺取)相关的知识,希望对你有一定的参考价值。

LINK

选择的点需要满足以下要求

Ⅰ.在第一棵树上是深度递减的一条连续链

Ⅱ.在第二棵树上不能互为子树中的点

考虑在第一棵树上 d f s dfs dfs,那么可以看作一个尺取一条链的过程,这样保证了在第一棵树上是合法的

若加入当前点 u u u在第二棵树不满足条件,那么尺取的链的顶点往下挪…

如何判断

判断是否在第二棵树满足条件,也就是考虑第二棵树上,判断当前尺取链的点是否是 u u u的子树或祖先

于是我们可以处理出第二棵树的 d f s dfs dfs序,这样就可以用线段树给某个点子树内的节点赋值

加入点 v v v的时候就把 v v v子树内的点区间加 1 1 1

这样是否能加入 u u u,就是看一下当前节点 u u u的子树在线段树上是否有值即可(同时覆盖是否是子树/祖先两个条件)

然而,虽然尺取复杂度很低,但是在树上需要回溯,这样总是会回退反复尺取复杂度

我们可以对每个点建立主席树,保存从根节点到自己的线段树状态,这样就能得到某段链的线段树状态

于是 d f s dfs dfs的时候开个栈保存从根节点到自己的节点,然后定义 u p [ v ] up[v] up[v]表示 v v v点向上最多能延申到 u p [ v ] up[v] up[v]点刚好不满足条件

于是 u u u可以直接在 u p [ f a u ] up[fa_u] up[fau] u u u的这段链去二分点,取出这点到 u u u的线段树看是否满足第二棵树

满足就往上面二分,否则往下面二分

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
const int N = maxn*100;
int n;
vector<int>vec1[maxn],vec2[maxn];
int root[maxn],ls[N],rs[N],sum[N],laz[N],id;
void update(int &rt,int pre,int l,int r,int L,int R,int val)//区间加val 
{
	rt = ++id, ls[rt] = ls[pre], rs[rt] =rs[pre], sum[rt] = sum[pre], laz[rt] = laz[pre];
	sum[rt] += ( min( r,R )-max( l,L )+1 )*val;
	if( l>=L && r<=R ) { laz[rt] += val; return; }
	int mid = l+r>>1;
	if( mid>=L )	update( ls[rt],ls[pre],l,mid,L,R,val );
	if( mid+1<=R )	update( rs[rt],rs[pre],mid+1,r,L,R,val );
}
int ask(int &rt,int pre,int l,int r,int L,int R)//询问区间[L,R]的值是多少 
{
	if( l>=L && r<=R )	return sum[rt]-sum[pre];
	int ans = ( laz[rt]-laz[pre] )*( min(r,R)-max(l,L)+1 ), mid = l+r>>1;
	if( mid>=L )	ans += ask( ls[rt],ls[pre],l,mid,L,R );
	if( mid+1<=R )	ans += ask( rs[rt],rs[pre],mid+1,r,L,R );
	return ans;
}
int dfsid,dfn[maxn],low[maxn];
void getdfsid(int u,int fa)
{
	dfn[u] = ++dfsid;
	for(auto v:vec2[u] ){ if( v==fa )	continue; getdfsid( v,u ); }
	low[u] = dfsid;
}
void predfs(int u,int fa)
{
	update( root[u],root[fa],1,n,dfn[u],low[u],1 );
	for(auto v:vec1[u] ){ if( v==fa )	continue; predfs( v,u ); }
}
int up[maxn],sta[maxn],top,ans;
void dfs(int u,int fa)
{
	sta[++top] = u;
	int l = up[fa], r = top-1; up[u] = top;
	while( r>=l )
	{
		int mid = l+r>>1;
		if( ask( root[fa],root[sta[mid]],1,n,dfn[u],low[u]) )	l = mid+1;
		else	r = mid-1, up[u] = mid;
	}
	ans = max( ans,top-up[u] );
	for(auto v:vec1[u] )
	{
		if( v==fa )	continue;
		dfs( v,u );
	}
	top--;
}
void init()
{
	for(int i=0;i<=id;i++)	ls[i] = rs[i] = sum[i] = laz[i] = root[i] = 0;
	dfsid = ans = id = 0;
	for(int i=1;i<=n;i++)	vec1[i].clear(), vec2[i].clear();
}
int main()
{
	int t; cin >> t;
	while( t-- )
	{
		cin >> n;
		for(int i=1;i<n;i++)
		{
			int l,r; scanf("%d%d",&l,&r);
			vec1[l].push_back( r ); vec1[r].push_back( l );
		}
		for(int i=1;i<n;i++)
		{
			int l,r; scanf("%d%d",&l,&r);
			vec2[l].push_back( r ); vec2[r].push_back( l );
		}
		getdfsid( 1,0 ); predfs( 1,0 );	dfs( 1,0 );
		cout << ans << endl;
		init();
	}
}

以上是关于2021牛客暑期多校训练营7 F.xay loves trees(主席树+树上尺取)的主要内容,如果未能解决你的问题,请参考以下文章

牛客多校2021 F.xay loves trees(树状数组+树上的滑动窗口)

牛客多校7.F.xay loves trees 主席树+dfs序

2021牛客暑期多校训练营7 J. xay loves Floyd 预处理最短路+bitset

2021牛客暑期多校训练营7xay loves trees(dfs序,维护根出发的链)

2021牛客暑期多校训练营7,签到题FHI

2021牛客暑期多校训练营7 部分题题解