CF 1529E. Trees of Tranquillity

文章目录

  • 题意:
  • 题解:
  • 代码:
    • 线段树代码:
    • 利用set实现

题意:

有A1,A2两棵树,根是1,编号都是1~n,先制作图A3,如果两个点的x和y同时满足以下两个条件则连边,
1.在树A中x是y的祖先或者y是x的祖先
2.在树B中x和y谁都不是谁的祖先
求A3的最大的团集的大小
团:图G的一个完全子图
题目A1和A2的输入方式为:
a2,a3…an, ai是树的顶点i的父亲节点(1<= ai <i)

题解:

参考题解:
文章1
文章2
我们需要将题意转化:
满足最大团的点是什么样的?团要求任意两点都有连线,也就是最大团中所有点同时满足题目说的两个条件,因此这些点在A树上是一条的(没有分支)。在B树上体现为彼此不是父亲节点,我们引入dfs序,发现所有点的dfs序没有交集。
对于本题的输入还有一个特殊性质:ai <i,说明A树和B树从根节点出发的链,一定是一个单调递增的序列。针对B树的dfs序区间,就会有:序号较小的点的区间,要么包含序号较大的点的区间,要么与其不相交
对于两个点的dfs序区间,要么没有交集(不是父子关系),要么存在包含(父子关系),且左端点与右端点是对应的,父亲系节点的区间包含儿子节点的区间,因此对于一个互相包含的区间,我们要保留较小的(这样才能存下更多不相交的区间),对应到树上,相当于 当一个点的儿孙可选时该点不选最优
现在我们从第一棵树的根开始dfs,每到一个点就往某数据结构中加入自己的区间:
1.如果被数据结构中原先的更大区间包含,那就删除大区间,加入小区间
2.如果包含了原有的至少一个小区间,那就不加
3.否则就加进去,答案+1
回溯时,数据结构要退回原来的状态

这个某数据结构可以用set,线段树等等
线段树具体实现过程:
先求树2的dfs序,然后对树1从根节点开始,查看当前点u的区间内是否有区间,如果没有直接插入,如果有,一定是比自己大的区间,所以删除原大区间,加入新区间。记录当前答案最大值,对u的儿子继续查找。回溯时逆向操作

代码:

线段树代码:

代码里有注释

#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) {//求树2的dfs序 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);//对u的儿子节点继续查找 }//回溯操作 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()
{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;
}

利用set实现

#include<set>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 300005
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
#define SI set<int>::iterator
LL read() {LL f = 1,x = 0;char s = getchar();while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}return f * x;
}
int n,m,i,j,s,o,k;
vector<int> g0[MAXN];
int L[MAXN],R[MAXN],lR[MAXN],tim;//lR[]数组是为L找到唯一的R
void dfs0(int x,int ff) {//求 树2的dfs序 L[x] = ++ tim;for(int i = 0;i < (int)g0[x].size();i ++) {if(g0[x][i] != ff) dfs0(g0[x][i],x);}R[x] = tim; lR[L[x]] = R[x];return ;
}
vector<int> g[MAXN];
int d[MAXN],dfn[MAXN],rr[MAXN],cnt,ans;
set<int> st;
void dfs(int x,int ff) {int ad = 0;if(st.empty()) st.insert(L[x]);//如果此时为空,直接插入 else {SI i = st.lower_bound(L[x]);//查找是否已经有区间 if(i != st.begin()) //发现有区间 {i --;if(lR[*i] >= R[x])//存在更大区间包含 {ad = *i;st.erase(ad);//删除大区间 st.insert(L[x]);//加入小区间 }else {i ++;if(i == st.end() || *i > R[x]) //里面没有小区间,加入的区间不会相交 st.insert(L[x]);}}else if(i == st.end() || *i > R[x]) st.insert(L[x]);//发现没区间 }ans = max(ans,(int)st.size());for(int i = 0;i < (int)g[x].size();i ++) {if(g[x][i] != ff) dfs(g[x][i],x);}//回溯操作 if(st.find(L[x]) != st.end()) st.erase(L[x]);if(ad) st.insert(ad);return ;
}
int main() {int T = read();while(T --) {n = read();tim = 0; cnt = 0;st.clear();for(int i = 1;i <= n;i ++) {g0[i].clear();g[i].clear();lR[i] = 0;}for(int i = 2;i <= n;i ++) {s = read(); g[s].push_back(i);}for(int i = 2;i <= n;i ++) {s = read(); g0[s].push_back(i);}dfs0(1,0);ans = 0;dfs(1,0);printf("%d\n",ans);}return 0;
}

CF 1529E. Trees of Tranquillity相关推荐

  1. CodeForces - 1529E Trees of Tranquillity(贪心+线段树)

    题目链接:https://vjudge.net/problem/CodeForces-1529E 题目大意:给出两棵根节点为 111 的树,分别称为 AAA 树和 BBB 树,现在通过两棵树可以构造出 ...

  2. 树上问题 ---- Codeforces Round #722 (Div. 1) C. Trees of Tranquillity [dfs序区间的性质+最大不相交区间的性质]

    题目链接 题目大意: 解题思路: 1.首先我们知道最大团里面的点全都是S树的一条路径上的点,但是也要满足在K树上不存在祖先关系. 2.对于祖先关系,我们发现对于一棵树上的dfs序,他们是包含关系的,就 ...

  3. xay loves trees

    xay loves trees 题意: 有两棵树,现在让你找到一个最大的点集合S,要求S中的点在第一棵树中任意两点存在祖先儿子关系且所有点是连接的,在第二棵树中任意两点都不存在祖先儿子关系,问S集合的 ...

  4. [CF/AT]各大网站网赛 体验部部长第一季度工作报告

    文章目录 CodeForces #712 (Div. 1)--1503 A. Balance the Bits B. 3-Coloring C. Travelling Salesman Problem ...

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

    F xay loves trees 题意: 给出两棵树,由这两棵树根据规则可以生成一个图,规则如下:如果u , v在第一棵树中满足其中一个点是另一个点祖先且最终所有所选的点都互相联通,在第二棵树中满足 ...

  6. CF1528C dfs序+set维护

    传送门 文章目录 题意: 思路: 题意: 给你两棵有nnn个节点的树,我门记第一棵为aaa,第二棵为bbb,现在你有一个nnn个点都孤立的点集,两个点u,vu,vu,v可以连边当且仅当这两个点在aaa ...

  7. Codeforces Round #722 (Div. 2)

    Codeforces Round #722 (Div. 2) 题号 题目 知识点 A Eshag Loves Big Arrays(题解略) 贪心 B Sifid and Strange Subseq ...

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

    题号 标题 已通过代码 通过率 团队的状态 A xay loves connected graphs 点击查看 7/117 未通过 B xay loves monotonicity 点击查看 39/3 ...

  9. CF#420 B. Okabe and Banana Trees 思维|暴力|几何

    Okabe needs bananas for one of his experiments for some strange reason. So he decides to go to the f ...

最新文章

  1. Runtime.getRuntime()
  2. 10个免费的javascript富文本编辑器(jQuery and non-jQuery)
  3. enterpriseTECH Dec 11
  4. 200 道算法面试题集锦!Python 实现,含华为、BAT 等校招真题!
  5. (转)深入理解最强桌面地图控件GMAP.NET --- 原理篇
  6. python正确方法_下列定义函数的方法,在Python中正确的是()。
  7. 【代码源 Div1 - 102】#323. 最长因子链(dp)
  8. 如何实现复杂FPGA设计的时序收敛
  9. window python环境搭建_Python入门-环境搭建详解(Window平台)
  10. 论文赏析[EACL17]K-best Iterative Viterbi Parsing(K-best迭代维特比句法分析)
  11. CH Round #56 - 国庆节欢乐赛解题报告
  12. 【luogu P2939 [USACO09FEB]改造路Revamping Trails】 题解
  13. matlab nist接口文件,Matlab调用refprop教程说明
  14. winpe加载raid_windows pe3.0加载RAID驱动!
  15. 机器视觉中常用图像处理库都有哪些?
  16. ibm vios_使用IBM地理分散弹性解决方案在生产现场保留冗余VIOS配置
  17. 关于在JS中引入JS文件的JQ方法
  18. Android应用主界面底部菜单实现
  19. Android 文字测量
  20. Android 热修复原理篇及几大方案比较

热门文章

  1. 神PS!老爸把儿子的画作P成现实,看完我笑哭了
  2. 梦真的是反的 | 今日最佳
  3. python求导函数的值_python怎么实现函数求导
  4. java 位运算_java学习之运算符与表达式(四)
  5. html中label的寬度無法修改,如何设置HTML span、label 的宽度
  6. java不朽神迹,不朽的神迹 Eternal Legacy HD v1.0.8
  7. mysql anyvalue函数_Mysql 的ANY_VALUE()函数和 ONLY_FULL_GROUP_BY 模式
  8. leetcode337. 打家劫舍 III
  9. leetcode435. 无重叠区间
  10. mysql下载了解压版怎么_教你安装Mysql(解压版/非安装包)图文教程