【FJWC 2019】 森林
【FJWC 2019】 森林

样例输入
0
5
1 0 0 2
样例输出
1
2
3
3
我们发现,答案就是直径加上直径上某个点出发,不经过其他直径上的点的最长链。这里的直径可以是任意一条直径。
首先我们每次只加一个点,所以我们很好维护新的直径。假设旧直径的两个端点是\((A,B)\),则加入点\(X\)后新的端点可能是\((A,B),(A,X),(B,X)\)。
然后我们考虑求“直径上某个点出发,不经过其他直径上的点的最长链”。
我们知道,\(Lct\)有虚边和实边。我们给每个节点开一个\(multiset\)维护虚子树贡献的最长链。
我们记录\(mx_v\)表示\(v\)所在\(splay\)中所有虚儿子贡献的最长链。\(lmx_v\)表示\(v\)所在\(splay\)的从最左端点出发,经过一段实边,再经过一段虚边的最长路径;\(rmx_v\)同理。
很显然,\(v\)所在这条实链的顶端到子树内的最长链就是\(lmx_v\)。记录\(lmx_v\)是为了在\(access\)操作的时候维护向其父亲贡献的最长链。
我们询问的时候就先\(MakeRoot(A)\),再\(access(B)\),这样\(A\to B\)的直径在一条实链上,答案就是\(dis_{A,B}+mx_A-[mx_A!=0]\)。
因为有\(MakeRoot\)操作,所以我们要维护\(rmx\),\(reverse\)的时候还要交换\(lmx,rmx\)。
可以参考【清华集训2016】数据交互
注意:\(push\_down(v)\)的时候要将左右儿子的\(lmx\)和\(rmx\)也交换了,否则\(update\)的时候会出错。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 400005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
multiset<int>st[N];
int n;
int ans;
int A,B;
int rev[N],fa[N],ch[N][2];
int lmx[N],rmx[N],mx[N];
int size[N];
#define ls ch[v][0]
#define rs ch[v][1]
void update(int v) {
size[v]=size[ls]+size[rs]+1;
mx[v]=max(*(--st[v].end()),max(mx[ls],mx[rs]));
lmx[v]=*(--st[v].end())+size[ls];
rmx[v]=*(--st[v].end())+size[rs];
lmx[v]=max(lmx[v],lmx[ls]);
rmx[v]=max(rmx[v],rmx[rs]);
if(rs) lmx[v]=max(lmx[v],lmx[rs]+size[ls]+1);
if(ls) rmx[v]=max(rmx[v],rmx[ls]+size[rs]+1);
}
void Rev(int v) {
rev[v]^=1;
swap(ls,rs);
swap(lmx[v],rmx[v]);
}
void down(int v) {
if(rev[v]) {
/*************/
Rev(ls);
Rev(rs);
rev[v]=0;
}
}
bool isroot(int v) {return v!=ch[fa[v]][0]&&v!=ch[fa[v]][1];}
void rot(int v) {
int f=fa[v],gr=fa[f];
int sn=v==ch[f][1],son=ch[v][!sn];
if(!isroot(f)) ch[gr][f==ch[gr][1]]=v;
ch[f][sn]=son;
ch[v][!sn]=f;
if(son) fa[son]=f;
fa[v]=gr;
fa[f]=v;
update(f);
update(v);
}
void Splay(int v) {
static int st[N],top;
top=0;
st[++top]=v;
for(int i=v;!isroot(i);i=fa[i]) st[++top]=fa[i];
while(top) down(st[top--]);
while(!isroot(v)) {
int f=fa[v],gr=fa[f];
if(!isroot(f)) rot(v==ch[f][1]^f==ch[gr][1]?v:f);
rot(v);
}
}
void Insert(int v,int f) {st[f].insert(lmx[v]+1);}
void Del(int v,int f) {st[f].erase(st[f].find(lmx[v]+1));}
void access(int v) {
int tem=0;
while(v) {
Splay(v);
if(tem) Del(tem,v);
if(rs) Insert(rs,v);
rs=tem;
update(v);
tem=v;
v=fa[v];
}
}
void Make_root(int v) {
access(v);
Splay(v);
Rev(v);
}
void Link(int v,int f) {
update(v);
access(f);
Splay(f);
fa[v]=f;
Insert(v,f);
update(f);
}
namespace DIS {
int dep[N],fa[N][20];
int mxdis=0;
int lca(int a,int b) {
if(dep[a]<dep[b]) swap(a,b);
for(int i=18;i>=0;i--)
if(fa[a][i]&&dep[fa[a][i]]>=dep[b])
a=fa[a][i];
if(a==b) return a;
for(int i=18;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
int dis(int a,int b) {return dep[a]+dep[b]-2*dep[lca(a,b)];}
void Insert(int v,int f) {
fa[v][0]=f;
for(int i=1;i<=18;i++) fa[v][i]=fa[fa[v][i-1]][i-1];
dep[v]=dep[f]+1;
int da=dis(A,v),db=dis(B,v);
mxdis=max(mxdis,max(da,db));
if(da==mxdis) B=v;
else if(db==mxdis) A=v;
}
}
int main() {
int cas=Get();
n=Get();
for(int i=1;i<=n;i++) st[i].insert(0);
A=B=1;
for(int i=2;i<=n;i++) {
int a=Get()^ans;
DIS::Insert(i,a);
Link(i,a);
Make_root(A);
access(B);
Splay(B);
cout<<(ans=DIS::mxdis+mx[B]-(mx[B]!=0))<<"\n";
}
return 0;
}
【FJWC 2019】 森林的更多相关文章
- 【FJWC 2019】min
[FJWC 2019]min 题目描述 给你一张 \(n\) 个点 \(m\) 条边的无向图,走过每条边都需要花费 \(1\) 秒. 给你一个整数 \(k\) ,请你选择至多 \(k\) 个点,令经过 ...
- FJWC 2019 游记
FJWC 2019 游记 Day 0 春节旅游, 刚从杭州绍兴一带赶回来, 然而并没有直接飞去福州, 去了厦门再去福州, 浪费了好多时间. Day 1 酒店到学校有 \(20\) 分钟的步行路程, 感 ...
- 【NOI2019模拟2019.7.1】为了部落 (生成森林计数,动态规划)
Description: \(1<=n<=1e9,1<=m,k<=100\) 模数不是质数. 题解: 先选m个点,最后答案乘上\(C_{n}^m\). 不妨枚举m个点的度数和D ...
- 「ZJOI2016」大森林 解题报告
「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...
- 先森林后树木:Elasticsearch各版本升级核心内容必看
在学习Elasticsearch 时候,因为各个版本的问题,搞不清,非常的头疼,官方也给出了各个版本更新的情况,不过是英文版本,版本更新信息又特别多,最近学习,看了很多资料,没有一个整理很清楚的,然后 ...
- 【主席树启发式合并】【P3302】[SDOI2013]森林
Description 给定一个 \(n\) 个节点的森林,有 \(Q\) 次操作,每次要么将森林中某两点联通,保证操作后还是个森林,要么查询两点间权值第 \(k\) 小,保证两点联通.强制在线. L ...
- 2019/8/27 Test(luogu 五月天模拟赛)
\(2019/8/27\)大考 \(\color{#ff0808}{\text{初二诀别赛(SAD)}}\) 题目名称 链接 寿司 \(BSOJ5111\) 秀秀的森林 \(BSOJ5125\) 分组 ...
- HNOI 2019 多边形
HNOI 2019 多边形 题意 小 R 与小 W 在玩游戏. 他们有一个边数为\(n\)的凸多边形,其顶点沿逆时针方向标号依次为\(1,2,3...n\).最开始凸多边形中有\(n\)条线段,即多边 ...
- [白话解析] 通俗解析集成学习之bagging,boosting & 随机森林
[白话解析] 通俗解析集成学习之bagging,boosting & 随机森林 0x00 摘要 本文将尽量使用通俗易懂的方式,尽可能不涉及数学公式,而是从整体的思路上来看,运用感性直觉的思考来 ...
随机推荐
- [日常]nginx与网络事件模型
Nginx 的特点: 1.处理静态文件 2.反向代理加速 3.fastCGI,简单的负载均衡和容错 4.模块化的结构 5.分阶段资源分配技术,使得它的 CPU 与内存占用率非常低,保持 10,000 ...
- git获取远程服务器的指定分支
昨天糗大了...进入新公司,公司服务器上有Online为线上版本,开发版本默认的为Master,本地clone的开发版为master,公司用的git 自动部署(puh后服务器自动更新了代码...这个有 ...
- [leetcode](4.21)3. 最长重复子串
给定字符串 S,找出最长重复子串的长度.如果不存在重复子串就返回 0. 示例 1: 输入:"abcd" 输出:0 解释:没有重复子串. 示例 2: 输入:"abbaba& ...
- 【JDK和Open JDK】平常使用的JDK和Open JDK有什么区别
注意到这个问题,是在CentOS7上安装JDK的时候,查找相关的资料,发现安装JDK之前都需要检查或卸载系统上原生的Open JDK,这才引起了注意. 到了这里,引用查到的一篇说明. 转自:http: ...
- 汇编语言--微机CPU的指令系统(五)(算术运算指令)
(3)算术运算指令 算术运算指令是反映CPU计算能力的一组指令,也是编程时经常使用的一组指令.它包括:加.减.乘.除及其相关的辅助指令. 该组指令的操作数可以是8位.16位和32位(80386+).当 ...
- CSS用法总结(持续更新)
一.html,body{height:100%} 解决了容器高度不足(容器高度由子元素高度决定,而%按照父元素的百分比),无法用%布局页面的问题 把html和body的高度设置为浏览器高度,此时会出现 ...
- 网页字体在Frontpage2000制作网页中的讲解
运用HTML,我们可以对字体的大小及字形进行简单的修改,但要进行统一地控制.创建特殊效果,就必须要用到CSS.它能让您更有效地控制网页外观,并可以扩充精确指定网页元素位置,外观以及创建特殊效果的能力. ...
- 实现响应式——CSS变量
CSS 变量是 CSS 引入的一个新特性,目前绝大多数浏览器已经支持了,它可以帮助我们用更少的代码写出同样多的样式,大大提高了工作效率,本篇文章将教你如何使用 CSS 变量(css variable) ...
- K8S 高级调度方式
可以使用高级调度分为: 节点选择器: nodeSelector.nodeName 节点亲和性调度: nodeAffinity Pod亲和性调度:PodAffinity Pod反亲和性调度:podAnt ...
- 生理周期POJ 1006
Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 138101 Accepted: 44225 Description 人生 ...