CodeForces - 1529E Trees of Tranquillity(贪心+线段树)
Posted Frozen_Guardian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces - 1529E Trees of Tranquillity(贪心+线段树)相关的知识,希望对你有一定的参考价值。
题目链接:https://vjudge.net/problem/CodeForces-1529E
题目大意:给出两棵根节点为 1 1 1 的树,分别称为 A A A 树和 B B B 树,现在通过两棵树可以构造出一个无向图,当且仅当点对 ( x , y ) (x,y) (x,y) 同时满足以下两个条件时,可以在图中建边:
- 在 A A A 树中, x x x 是 y y y 的祖先或 y y y 是 x x x 的祖先
- 在 B B B 树中, x x x 不能是 y y y 的祖先同时 y y y 不能是 x x x 的祖先
求该图的最大团
题目分析:一开始读错题了,后来读对题后分析的差不多时间也到点了,今天补题的时候发现和赛场的思路差的不算太多,就是一个挺简单的贪心
思考一下,满足最大团的点,在 A A A 树上和 B B B 树上的形态是什么样的,首先这些点在 A A A 树上一定是一条,从根节点到叶子结点的链上的点,可以不连续。在 B B B 树上就可以体现为,所有点的 d f s dfs dfs 序都没有交集
继续分析,所有点的 d f s dfs dfs 序没有交集,也就是说需要选择尽可能多的区间,使其互不相交,这样就将树上的问题转换成线性问题了
而在 A A A 树上需要满足所有的点在同一条链上,在 d f s dfs dfs 的时候贪心选择尽可能多的点就可以了
然后是题目针对于本题输入的一个特殊性质,基于给出的树的输入方式,是每次给出点 i i i 的父节点。这也就使得, A A A 树和 B B B 树从根节点拉下来的一条链,一定是一个单调递增的序列,结合于此,针对于 B B B 树的 d f s dfs dfs 序的区间,有一个下面会用到的性质:
序号较小的点的区间,要么包含序号较大的点的区间,要么与其不相交
接下来就可以对 A A A 树 d f s dfs dfs 去贪心了,需要维护一个数据结构,需要实现以下功能:
- 插入一个区间
- 删除一个区间
- 判断存在的区间是否存在交集
可以用平衡树(set),也可以用线段树,我觉得用线段树比较好理解,就选择了线段树实现
当遍历到点 x x x 时,尝试将点 x x x 所代表的区间插入到线段树中,无非会出现三种情况:
- [ L [ x ] , R [ x ] ] [L[x],R[x]] [L[x],R[x]] 中原先并没有区间,则直接插入即可
- [ L [ x ] , R [ x ] ] [L[x],R[x]] [L[x],R[x]] 被一个更大的区间覆盖,则将其删掉,并替换上点 x x x 所代表的区间显然更优
- [ L [ x ] , R [ x ] ] [L[x],R[x]] [L[x],R[x]] 中包含了大于一个区间,此时如果想加入 x x x 所代表的区间,就需要将冲突的区间全都删掉,显然舍弃掉 x x x 所代表的区间是更优的,实际操作就是,无需操作
回溯的时候将 x x x 所代表的区间按照上述三种情况还原即可
最后的最后还有一个比较难解决的小问题,就是,如何快速查询区间 [ L [ x ] , R [ x ] ] [L[x],R[x]] [L[x],R[x]] 中存在的不同区间的个数,以及如何快速更新线段树
还记得前面加粗的性质吗?序号大小这个条件还没有用上呢
其实我们可以直接去查询 [ L [ x ] , R [ x ] ] [L[x],R[x]] [L[x],R[x]] 中,存在的区间的最大编号即可,因为在 A A A 树上 d f s dfs dfs 遍历的链也是递增遍历的,结合加粗的性质,如果 [ L [ x ] , R [ x ] ] [L[x],R[x]] [L[x],R[x]] 之前被覆盖过,那么一定是一个更大的区间覆盖的,所以上述的三种情况里,第三种情况实际上根本不可能出现
代码:
// Problem: E. Trees of Tranquillity
// Contest: Codeforces - Codeforces Round #722 (Div. 2)
// URL: https://codeforces.com/contest/1529/problem/E
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
T f=1;x=0;
char ch=getchar();
while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
x*=f;
}
template<typename T>
inline void write(T x)
{
if(x<0){x=~(x-1);putchar('-');}
if(x>9)write(x/10);
putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
vector<int>a[N],b[N];
int L[N],R[N],dfn,sum,ans;
struct Node {
int l,r,mmax,lazy;
}tree[N<<2];
void pushup(int k) {
tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);
}
void pushdown(int k) {
if(tree[k].lazy!=-1) {
int lz=tree[k].lazy;
tree[k].lazy=-1;
tree[k<<1].mmax=tree[k<<1|1].mmax=lz;
tree[k<<1].lazy=tree[k<<1|1].lazy=lz;
}
}
void build(int k,int l,int r) {
tree[k]={l,r,0,-1};
if(l==r) {
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
void update(int k,int l,int r,int val) {
if(tree[k].l>r||tree[k].r<l) {
return;
}
if(tree[k].l>=l&&tree[k].r<=r) {
tree[k].mmax=tree[k].lazy=val;
return;
}
pushdown(k);
update(k<<1,l,r,val);
update(k<<1|1,l,r,val);
pushup(k);
}
int query(int k,int l,int r) {
if(tree[k].l>r||tree[k].r<l) {
return 0;
}
if(tree[k].l>=l&&tree[k].r<=r) {
return tree[k].mmax;
}
pushdown(k);
return max(query(k<<1,l,r),query(k<<1|1,l,r));
}
void dfs1(int u) {
L[u]=++dfn;
for(auto v:b[u]) {
dfs1(v);
}
R[u]=dfn;
}
void dfs2(int u) {
int mmax=query(1,L[u],R[u]);
if(!mmax) {
update(1,L[u],R[u],u);
sum++;
} else {
update(1,L[mmax],R[mmax],0);
update(1,L[u],R[u],u);
}
ans=max(ans,sum);
for(auto v:a[u]) {
dfs2(v);
}
if(!mmax) {
update(1,L[u],R[u],0);
sum--;
} else {
update(1,L[u],R[u],0);
update(1,L[mmax],R[mmax],mmax);
}
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int w;
cin>>w;
while(w--) {
int n;
read(n);
dfn=0;
for(int i=1;i<=n;i++) {
a[i].clear();
b[i].clear();
}
for(int i=2;i<=n;i++) {
int fa;
read(fa);
a[fa].push_back(i);
}
for(int i=2;i<=n;i++) {
int fa;
read(fa);
b[fa].push_back(i);
}
dfn=ans=sum=0;
build(1,1,n);
dfs1(1);
dfs2(1);
cout<<ans<<endl;
}
return 0;
}
以上是关于CodeForces - 1529E Trees of Tranquillity(贪心+线段树)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 633G Yash And Trees bitset + 线段树
codeforces 917D Stranger Trees
CodeForces - 402B Trees in a Row (暴力)
CodeForces596D Wilbur and Trees