CF1528C Trees of Tranquillity

小清新找性质题,想到关键就很简单

考虑在第一棵树上枚举一条从 \(1\) 到某个点的链,显然这些点之间满足第一个限制,现在只要在这些点中选出尽可能多的点满足第二个限制即可

在第二棵树上两个点没有祖先关系,等价于它们对应的 DFS 序区间相离

而两个点的 DFS 序区间显然要么相离要么包含,在出现包含的情况时舍去大的那个即可

set 维护区间,复杂度 \(O(n\log n)\)

#include<cstdio>
#include<iostream>
#include<set>
#include<vector>
#define RI register int
#define CI const int&
#define fi first
#define se second
using namespace std;
typedef pair <int,int> pi;
const int N=300005;
int t,n,x,ans,idx,L[N],R[N]; vector <int> A[N],B[N]; set <pi> s;
inline void DFS1(CI now=1)
{
    L[now]=++idx; for (auto to:B[now]) DFS1(to); R[now]=idx;
}
inline void DFS2(CI now=1)
{
    bool is_insert=0,is_delete=0; pi tmp;
    auto it=s.lower_bound({L[now],0});
    if (it!=s.end()&&it->se<R[now])
    {
        // don't insert this interval
    } else
    {
        if (it!=s.begin())
        {
            --it;
            if (it->fi<=L[now]&&R[now]<=it->se)
            {
                is_delete=1; tmp=*it;
                s.erase(it);
            }
        }
        is_insert=1; s.insert({L[now],R[now]});
    }
    ans=max(ans,(int)s.size());
    for (auto to:A[now]) DFS2(to);
    if (is_insert) s.erase({L[now],R[now]});
    if (is_delete) s.insert(tmp);
}
int main()
{
    for (scanf("%d",&t);t;--t)
    {
        scanf("%d",&n); ans=idx=0; s.clear();
        for (RI i=1;i<=n;++i) A[i].clear(),B[i].clear();
        for (RI i=2;i<=n;++i) scanf("%d",&x),A[x].push_back(i);
        for (RI i=2;i<=n;++i) scanf("%d",&x),B[x].push_back(i);
        DFS1(); DFS2(); printf("%d\n",ans);
    }
    return 0;
}
posted @ 2024-08-14 19:05  空気力学の詩  阅读(24)  评论(0编辑  收藏  举报