Codeforces 题目传送门 & 洛谷题目传送门

*3400 的毒瘤 H 题,特意写个题解纪念一下(

首先对于这种数据结构不太好直接维护的东东可以考虑分块。然鹅我除了分块其他啥也没想到

我们设一个阈值 \(B\),每 \(B\) 个元素分为一块。

我们知道两点之间的 LCA 的大体思想肯定是暴力跳祖先,直到两点重合为止。不过由于此题修改操作的特殊性,什么倍增、树剖都萎掉了。

于是我们考虑一个大致思路:整块暴力跳,散块直接找祖先。

具体来说,我们设 \(pre_i\) 为 \(i\) 的祖先中最大的满足 \(j\) 与 \(i\) 不在同一块中的 \(j\)

假设我们已经维护好了 \(pre_i\),那么找两点 \(u,v\) 之间的 LCA 这样实现:

  • 如果 \(u,v\) 两点不在同一块,那我们就将较靠后的元素(不妨设为 \(u\))跳到 \(pre_u\)
  • 如果 \(u,v\) 两点在同一块,且 \(pre_u\ne pre_v\),那我们就令 \(u=pre_u,v=pre_v\)。
  • 如果 \(u,v\) 两点在同一块,且 \(pre_u=pre_v\),那我们就令 \(u,v\) 的较大者(不妨设为 \(u\))跳到其父亲为止。

正确性显然,如果你对树剖比较熟应该会理解得深刻一些。这部分复杂度 \(qB+\dfrac{qn}{B}\)。

接下来考虑修改操作,对于边角块,直接暴力修改其 \(a_i\) 值,然后对整块进行重构即可,这样最多只会重构两块,故这部分复杂度为单次询问 \(\mathcal O(B)\)。

对于整块,直接维护比较困难,不过注意到一个性质,那就是进行 \(B\) 次操作之后每个点的 \(fa\) 值都不会属于这个块,也就是说如果某个块的修改次数 \(\geq B\),那么 \(pre_i=fa_i\),故我们维护一个 \(cnt_i\) 表示每个块总共被改了多少次,如果 \(cnt_i\leq B\) 还是暴力重构整个块,否则打一个 \(+x\) 的标记,然后查询某个点的 \(pre\) 值时就返回 \(\max(1,pre_i-tag_i)\),其中 \(tag_i\) 为 \(i\) 所在的块打的标记大小。这部分复杂度为 \(B·\dfrac{n}{B}·B=nB\)

根据均值不等式可知 \(B=\sqrt{n}\) 时最优,总复杂度 \(n\sqrt{n}+q\sqrt{n}\)。

还有一些细节需注意,具体见代码罢:

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1e5;
const int SQRT=316;
int n,qu,fa[MAXN+5],pre[MAXN+5];
int blk_sz,blk,L[SQRT+5],R[SQRT+5],bel[MAXN+5];
int tag[SQRT+5],sum[SQRT+5];
void update(int x){
for(int i=L[x];i<=R[x];i++) fa[i]=max(1,fa[i]-tag[x]);
tag[x]=0;
for(int i=L[x];i<=R[x];i++){
if(fa[i]<L[x]) pre[i]=fa[i];
else pre[i]=pre[fa[i]];
}
}
int getpre(int x){return max(pre[x]-tag[bel[x]],1);}
int getfa(int x){return max(fa[x]-tag[bel[x]],1);}
void modify(int l,int r,int x){
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++) fa[i]=max(1,fa[i]-x);
update(bel[l]);return;
}
for(int i=l;i<=R[bel[l]];i++) fa[i]=max(1,fa[i]-x);
for(int i=L[bel[r]];i<=r;i++) fa[i]=max(1,fa[i]-x);
update(bel[l]);update(bel[r]);
for(int i=bel[l]+1;i<=bel[r]-1;i++){
tag[i]=min(n,tag[i]+x);sum[i]++;
if(sum[i]<=R[i]-L[i]+1) update(i);
}
}
int getlca(int u,int v){
while(u!=v){
if(bel[u]<bel[v]) swap(u,v);
if(bel[u]>bel[v]) u=getpre(u);
else{
if(getpre(u)==getpre(v)){
while(u!=v){
if(u<v) swap(u,v);
u=getfa(u);
}
} else {
u=getpre(u);v=getpre(v);
}
}
} return u;
}
int main(){
scanf("%d%d",&n,&qu);blk_sz=(int)pow(n,0.5);blk=(n-1)/blk_sz+1;
for(int i=1;i<=blk;i++){
L[i]=(i-1)*blk_sz+1;R[i]=min(i*blk_sz,n);
for(int j=L[i];j<=R[i];j++) bel[j]=i;
}
for(int i=2;i<=n;i++) scanf("%d",&fa[i]);
for(int i=1;i<=blk;i++) update(i);
while(qu--){
int opt;scanf("%d",&opt);
if(opt==1){int l,r,x;scanf("%d%d%d",&l,&r,&x);modify(l,r,x);}
else{int u,v;scanf("%d%d",&u,&v);printf("%d\n",getlca(u,v));}
}
return 0;
}

Codeforces 1491H - Yuezheng Ling and Dynamic Tree(分块)的更多相关文章

  1. Solution -「CF 1491H」Yuezheng Ling and Dynamic Tree

    \(\mathcal{Description}\)   Link. 做题原因:题目名.   给定一个长度 \(n-1\) 的序列 \(\{a_2,a_3,\cdots,a_n\}\),其描述了一棵 \ ...

  2. [cf1491H]Yuezheng Ling and Dynamic Tree

    将其按照区间分块(即$[(i-1)K+1,iK]$作为一个块),并定义$f_{x}$表示$x$的祖先中编号最小且与$x$在同一个块内的节点,$f_{x}$可以通过$f_{a_{x}}$转移,即$f_{ ...

  3. Codeforces 840D Expected diameter of a tree 分块思想

    Expected diameter of a tree 我们先两次dfs计算出每个点能到达最远点的距离. 暴力计算两棵树x, y连边直径的期望很好求, 我们假设SZ(x) < SZ(y) 我们枚 ...

  4. codeforces 1065F Up and Down the Tree

    题目链接:codeforces 1065F Up and Down the Tree 题意:给出一棵树的节点数\(n\)以及一次移动的最大距离\(k\),现在有一个标记在根节点1处,每一次可以进行一下 ...

  5. Codeforces 914H Ember and Storm's Tree Game 【DP】*

    Codeforces 914H Ember and Storm's Tree Game 题目链接 ORZ佬 果然出了一套自闭题 这题让你算出第一个人有必胜策略的方案数 然后我们就发现必胜的条件就是树上 ...

  6. Codeforces Round #499 (Div. 1) F. Tree

    Codeforces Round #499 (Div. 1) F. Tree 题目链接 \(\rm CodeForces\):https://codeforces.com/contest/1010/p ...

  7. Educational Codeforces Round 6 E. New Year Tree dfs+线段树

    题目链接:http://codeforces.com/contest/620/problem/E E. New Year Tree time limit per test 3 seconds memo ...

  8. Codeforces Round #353 (Div. 2) D. Tree Construction 二叉搜索树

    题目链接: http://codeforces.com/contest/675/problem/D 题意: 给你一系列点,叫你构造二叉搜索树,并且按输入顺序输出除根节点以外的所有节点的父亲. 题解: ...

  9. Codeforces Educational Codeforces Round 3 E. Minimum spanning tree for each edge LCA链上最大值

    E. Minimum spanning tree for each edge 题目连接: http://www.codeforces.com/contest/609/problem/E Descrip ...

随机推荐

  1. 配置pyenv环境

    git clone https://github.com/pyenv/pyenv.git ~/.pyenv echo 'export PYENV_ROOT="$HOME/.pyenv&quo ...

  2. Idea Maven auto Import

  3. OO第三单元

    OO第三单元 JML语言理论基础,应用工具链 JML语言基础 JML简介 定义: JML 是一种形式化的. 面向 JAVA 的行为接口规格语言 作用: 开展规格化设计.这样交给代码实现人员的将不是可能 ...

  4. SpringCloud 2020.0.4 系列之服务降级

    1. 概述 老话说的好:做人要正直,做事要正派,胸怀坦荡.光明磊落,才会赢得他人的信赖与尊敬. 言归正传,之前聊了服务间通信的组件 Feign,今天我们来聊聊服务降级. 服务降级简单的理解就是给一个备 ...

  5. golang常用库:cli命令行/应用程序生成工具-cobra使用

    golang常用库:cli命令行/应用程序生成工具-cobra使用 一.Cobra 介绍 我前面有一篇文章介绍了配置文件解析库 Viper 的使用,这篇介绍 Cobra 的使用,你猜的没错,这 2 个 ...

  6. 安装配置多个版本JDK

    前言:JDK有多个版本,有时为了开发需要切换不同的版本,在一部电脑上安装多个JDK,只需要按以下配置,每次即可轻松使用.以下环境为Windows10 安装JDK 安装JDK8 配置环境变量 需要配置J ...

  7. WLAN-无线路由综合应用

    一.实验目的 掌握综合应用的配置 二.实验仪器设备及软件 实验仪器设备:路由器.三层交换机.3台二层交换机.AC.3台AP 软件:ensp   三.实验原理   四.实验内容与步骤 AC配置: [AC ...

  8. Swift-技巧(三)使用元组(tuple)

    最近看 iOS 的官方功能的 Demo 时,发现代码中使用元组的地方很多,所以兴趣上来,查了下元组的出处. 在苹果的文档中就只有简短的两句,使用元组创建一个组合的值,从函数中返回多个值.元组中的可以使 ...

  9. 基于Dapr的 Azure 容器应用

    微软在 Ignite 2021 大会上发布了预览版的Azure Container Apps,这是一个完全托管的无服务器容器运行时间,用于大规模构建和运行现代应用程序.从2021 年 11 月 2 日 ...

  10. Linux&c 文件操作,线程进程控制,网络编程,简单知识点梳理

    一:文件操作 在linux下,一切皆文件,目录是文件,称为目录文件,内容是该目录的目录项(但是目录只有内核可以编辑,超级用户也不可以编辑),设备也是设备文件,在/dev存放的就是一些设备文件,linu ...