2021牛客暑期多校训练营7
时间:2021-08-09
本文章向大家介绍2021牛客暑期多校训练营7,主要包括2021牛客暑期多校训练营7使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
还是第一次做到这种两棵树(两个图)的题目,自然是不可能在两棵树上同时搞得,因为两棵树结构都不同....
题目要求选的点在第一棵树上必须是连续的链状,在第二棵树上任何两个点都不能是祖宗,祖先的关系,换句话说在第二棵树上,任何一个点都不能是另一个点的子树中的点。
既然第一棵树上的要求比较严苛,我们可以考虑在第一棵树上进行操作,将第二棵树上的要求当做第一棵树上的限制条件。
因为在第一棵树上必须是链,这很符合我们的dfs的要求,我们将树上的链转化成序列上的问题思考怎么解决,对于这种区间最长的问题,我们很容易想到尺取法,我们可以找一下每个右端点最小的左端点,发现当右指针递增时,左指针也一定递增。譬如当右指针为r时,左指针为l,则当右指针为r+1时,左指针左边的一定不用再考虑了,因为r已经在区间内了,而r和l左边的有冲突,所以左指针也一定递增。这就保证了我们的复杂度是O(n)的。我们把它放到树上,也就是说在dfs的时候维护一个左右指针就行,那怎么判断当前的序列合不合法?由于在第二棵树上,任何一个点都不能是另一个点的子树中的点,所以我们可以每次选择一个节点后都将这个节点及其字数都染色,之后判断一个点是否可进入我们的序列中时,我们只需要判断它的子树中是否有值即可。若有值则之前选的点中一定有它的祖先或儿子。这用dfs序加线段树就行。
//不等,不问,不犹豫,不回头. #include<bits/stdc++.h> #define _ 0 #define ls p<<1 #define db double #define rs p<<1|1 #define P 1000000007 #define ll long long #define INF 1000000000 #define get(x) x=read() #define PLI pair<ll,int> #define PII pair<int,int> #define ull unsigned long long #define put(x) printf("%d\n",x) #define putl(x) printf("%lld\n",x) #define rep(x,y,z) for(int x=y;x<=z;++x) #define fep(x,y,z) for(int x=y;x>=z;--x) #define go(x) for(RE int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y) using namespace std; const int N=3e5+10; int dfn[N],Size[N],num,b[N],ans,n; vector<int>v1[N],v2[N]; struct Tree { int l,r,tag,dat; #define l(x) t[x].l #define r(x) t[x].r #define tag(x) t[x].tag #define dat(x) t[x].dat }t[N<<2]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void init() { get(n); rep(i,1,n) v1[i].clear(),v2[i].clear(); rep(i,1,n-1) { int get(x),get(y); v1[x].push_back(y); v1[y].push_back(x); } rep(i,1,n-1) { int get(x),get(y); v2[x].push_back(y); v2[y].push_back(x); } } inline void dfs(int x,int father) { dfn[x]=++num;Size[x]=1; for(auto y:v2[x]) { if(y==father) continue; dfs(y,x); Size[x]+=Size[y]; } } inline void build(int p,int l,int r) { l(p)=l;r(p)=r; if(l==r) {dat(p)=tag(p)=0;return;} int mid=l+r>>1; build(ls,l,mid); build(rs,mid+1,r); dat(p)=tag(p)=0; } inline void push(int p) { if(tag(p)) { dat(ls)+=tag(p); dat(rs)+=tag(p); tag(ls)+=tag(p); tag(rs)+=tag(p); tag(p)=0; } } inline int ask(int p,int l,int r) { if(l<=l(p)&&r>=r(p)) return dat(p); push(p); int mid=l(p)+r(p)>>1; int ans=-INF; if(l<=mid) ans=max(ans,ask(ls,l,r)); if(r>mid) ans=max(ans,ask(rs,l,r)); return ans; } inline void alter(int p,int l,int r,int k) { if(l<=l(p)&&r>=r(p)) { dat(p)+=k; tag(p)+=k; return; } push(p); int mid=l(p)+r(p)>>1; if(l<=mid) alter(ls,l,r,k); if(r>mid) alter(rs,l,r,k); dat(p)=max(dat(ls),dat(rs)); } inline void dfs(int x,int father,int l,int r) { ans=max(ans,r-l+1); for(auto y:v1[x]) { if(y==father) continue; int L=l,R=r;//记录加入y之后的指针. while(ask(1,dfn[y],dfn[y]+Size[y]-1)) { alter(1,dfn[b[L]],dfn[b[L]]+Size[b[L]]-1,-1); L++; } alter(1,dfn[y],dfn[y]+Size[y]-1,1); b[++R]=y; dfs(y,x,L,R); rep(i,l,L-1) alter(1,dfn[b[i]],dfn[b[i]]+Size[b[i]]-1,1); alter(1,dfn[y],dfn[y]+Size[y]-1,-1); } } int main() { //freopen("1.in","r",stdin); int get(T); while(T--) { init(); num=0;dfs(1,0); build(1,1,n); ans=0;b[1]=1; alter(1,dfn[1],dfn[1]+Size[1]-1,1); dfs(1,0,1,1); put(ans); } return (0^_^0); } //以吾之血,铸吾最后的亡魂.
原文地址:https://www.cnblogs.com/gcfer/p/15117802.html
- hashpartitioner-Spark分区计算器
- Could not find artifact com.sun:tools:jar:1.5.0
- Java面试官最爱的volatile关键字
- Golang实现带优先级的channel
- java在指定目录下执行dos命令或者bat文件
- 搭建本地 golang 文档服务器
- 浅析Java中的final关键字
- 大话企业级android读书笔记(一)
- 转--Go语言用堆排序的方法进行一千万个int随机数排序
- go语言,变量引用的用法
- 大话企业级android读书笔记(三)
- Ubuntu 11.10 安装JDK
- Go- Buffer Channel- Select-基础理解
- Hadoop使用(一)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法