2021牛客暑期多校训练营7 F.xay loves trees(主席树+树上尺取)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营7 F.xay loves trees(主席树+树上尺取)相关的知识,希望对你有一定的参考价值。
选择的点需要满足以下要求
Ⅰ.在第一棵树上是深度递减的一条连续链
Ⅱ.在第二棵树上不能互为子树中的点
考虑在第一棵树上 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