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. Codeforces1575D

    思路分析 此题采用dfs,注意X选中了之后所有的X值相同,所以需要一个flag来存储X的值. 注意前导0要单独讨论,然后就是当'X'或者'_'在第一位时不能选0,其它位可以选0 - 9 任意一个数. ...

  2. UltraSoft - Alpha - Postmortem 事后分析

    Alpha阶段 Postmortem会议 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 主要是解决DDL提醒功能的问题,定义的比较清楚,对典型用户和典 ...

  3. Codeforces Round #573 (Div. 2) D题题解

    一.题目 ​ Tokitsukaze, CSL and Stone Game ​ Tokitsukaze和CSL正在玩一些石头游戏. ​ 一开始,有n堆的石头,第i堆石头数记为 \(a_i\),两人轮 ...

  4. BUAA2020软工作业(四)——结对项目

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结对项目作业 我在这个课程的目标是 进一步提高自己的编码能力,工程能力,团队协作能力 这个作业在哪 ...

  5. [火星补锅] 水题大战Vol.2 T2 && luogu P3623 [APIO2008]免费道路 题解

    前言: 如果我自己写的话,或许能想出来正解,但是多半会因为整不出正确性而弃掉. 解析: 这题算是对Kruskal的熟练运用吧. 要求一颗生成树.也就是说,最后的边数是确定的. 首先我们容易想到一个策略 ...

  6. [火星补锅] siano 神奇的线段树

    前言: 本来以为很难打的,没想到主干一次就打对了,然而把输入的b和d弄混了,这sb错误调了两个小时... 解析: 神奇的线段树.注意到有一个性质,无论怎么割草,生长速度快的一定不会比生长速度慢的矮.因 ...

  7. Spring Cloud Alibaba 使用RestTemplate进行服务消费

    创建服务提供者工程 创建spring-cloud-alibaba-service-member工程,会员中心服务该服务提供用户会员信息. pom.xml <?xml version=" ...

  8. void * 是什么?

    最近遇到void *的问题无法解决,发现再也无法逃避了(以前都是采取悄悄绕过原则),于是我决定直面它. 在哪遇到了? 线程创建函数pthread_create()的最后一个参数void *arg,嗯? ...

  9. 羽夏看Win系统内核——驱动篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  10. Apache Shiro 反序列化漏洞分析

    Shiro550 环境搭建 参考:https://www.cnblogs.com/twosmi1e/p/14279403.html 使用Docker vulhub中的环境 docker cp 将容器内 ...