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

(特别的,若$x$在第一个块中则$f_{x}=1$)

通过$f_{x}$,类似于树剖的方式,即若两者$f_{x}$不同则移动$f_{x}$较大的(移动到$f_{x}$),直至相同再用同样的方式爬$a_{x}$,复杂度显然是$o(q\sqrt{n})$的

接下来是如何维护$f_{x}$,即如何支持修改:

对于边角的两个块,显然是可以暴力维护的,对于整块修改,显然当一个块被修改$\sqrt{n}$次后一定有$f_{x}=x$,因此至多$o(n)$次暴力,复杂度也是$o(n\sqrt{n})$

最终总复杂度即为$o((n+q)\sqrt{n})$

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define N 100005
  4. 4 int n,m,K,p,x,y,z,a[N],bl[N],st[N],ed[N],f[N];
  5. 5 long long tag[N];
  6. 6 int get(int k){
  7. 7 return max(a[k]-tag[bl[k]],1LL);
  8. 8 }
  9. 9 void calc(int x,int y){
  10. 10 for(int i=x;i<=y;i++)
  11. 11 if (bl[i]==1)f[i]=1;
  12. 12 else{
  13. 13 int x=get(i);
  14. 14 if (bl[x]!=bl[i])f[i]=i;
  15. 15 else f[i]=f[x];
  16. 16 }
  17. 17 }
  18. 18 int main(){
  19. 19 scanf("%d%d",&n,&m);
  20. 20 for(int i=2;i<=n;i++)scanf("%d",&a[i]);
  21. 21 K=(int)sqrt(n);
  22. 22 for(int i=1;i<=n;i++)bl[i]=(i-1)/K+1;
  23. 23 for(int i=1;i<=bl[n];i++){
  24. 24 st[i]=(i-1)*K+1;
  25. 25 ed[i]=min(i*K,n);
  26. 26 calc(st[i],ed[i]);
  27. 27 }
  28. 28 calc(1,n);
  29. 29 for(int i=1;i<=m;i++){
  30. 30 scanf("%d%d%d",&p,&x,&y);
  31. 31 if (p==1){
  32. 32 scanf("%d",&z);
  33. 33 if (bl[x]==bl[y]){
  34. 34 for(int j=x;j<=y;j++)a[j]=max(a[j]-z,1);
  35. 35 calc(st[bl[x]],ed[bl[x]]);
  36. 36 }
  37. 37 else{
  38. 38 for(int j=x;j<=ed[bl[x]];j++)a[j]=max(a[j]-z,1);
  39. 39 calc(st[bl[x]],ed[bl[x]]);
  40. 40 for(int j=st[bl[y]];j<=y;j++)a[j]=max(a[j]-z,1);
  41. 41 calc(st[bl[y]],ed[bl[y]]);
  42. 42 for(int j=bl[x]+1;j<=bl[y]-1;j++){
  43. 43 tag[j]+=z;
  44. 44 if (tag[j]-z<=K)calc(st[j],ed[j]);
  45. 45 }
  46. 46 }
  47. 47 }
  48. 48 else{
  49. 49 while (f[x]!=f[y]){
  50. 50 if (f[x]>f[y])swap(x,y);
  51. 51 y=get(f[y]);
  52. 52 }
  53. 53 if (x==y){
  54. 54 printf("%d\n",x);
  55. 55 continue;
  56. 56 }
  57. 57 while (get(x)!=get(y)){
  58. 58 if (get(x)>get(y))swap(x,y);
  59. 59 y=get(y);
  60. 60 }
  61. 61 if (x==y)printf("%d\n",x);
  62. 62 else printf("%d\n",get(x));
  63. 63 }
  64. 64 }
  65. 65 }

[cf1491H]Yuezheng Ling and Dynamic Tree的更多相关文章

  1. Codeforces 1491H - Yuezheng Ling and Dynamic Tree(分块)

    Codeforces 题目传送门 & 洛谷题目传送门 *3400 的毒瘤 H 题,特意写个题解纪念一下( 首先对于这种数据结构不太好直接维护的东东可以考虑分块.然鹅我除了分块其他啥也没想到 我 ...

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

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

  3. 10+ 最流行的 jQuery Tree 菜单插件

    jstree – jQuery Tree Plugin With HTML & JSON Data jstree is a lightweight and flexible jQuery pl ...

  4. java基础十[包、Jar存档文件和部署](阅读Head First Java记录)

    将Java的class文件生成为可执行的Java应用程序.Java应用程序有三种:完全在本机执行的Jar(例如本机的GUI可执行程序):完全在服务器端远程执行的(例如浏览器来进行存取):介于两者之间的 ...

  5. FTP客户端上传下载Demo实现

    1.第一次感觉MS也有这么难用的MFC类: 2.CFtpFileFind类只能实例化一个,多个实例同时查找会出错(因此下载时不能递归),采用队列存储目录再依次下载: 3.本程序支持文件夹嵌套上传下载: ...

  6. [ActionScript 3.0] Away3D 官网实例

    /* Dynamic tree generation and placement in a night-time scene Demonstrates: How to create a height ...

  7. PeopleCode事件和方法只用于online界面不能用于组件接口(component interface)

    在使用CI过程中,哪些方法是不能使用的.以下为PeopleBook解释的内容. 一.搜索框代码不执行:SearchInit, SearchSave, and RowSelect events 意味着使 ...

  8. table2excel使用

    原table2excel代码 /* * 采用jquery模板插件——jQuery Boilerplate * * Made by QuJun * 2017/01/10 */ //table2excel ...

  9. dhtmlxtree 如何得到xml,json等文件中的自定义的属性值

    先看代码: var TreeForJSON = new dhtmlXTreeObject('TreeForJSON', '100%', '100%', 0); TreeForJSON.setImage ...

随机推荐

  1. 记一次 .NET 某电商定向爬虫 内存碎片化分析

    一:背景 1. 讲故事 上个月有位朋友wx找到我,说他的程序存在内存泄漏问题,寻求如何解决? 如下图所示: 从截图中可以看出,这位朋友对 windbg 的操作还是有些熟悉的,可能缺乏一定的实操经验,所 ...

  2. 讲讲java中线程池的实现

    今天跟一个同学谈到java中的线程池的实现,才发现有些知识点已经记不清了,所以特意把源码打开,对官方文档做了些说明. 其实这些理解了之后,读懂源码应该是没多大问题了,有感兴趣的小伙伴们可以看完说明后自 ...

  3. shell关键字含义

    linux中shell变量$#,$@,$0,$1,$2的含义解释: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行 ...

  4. try-catch-finally面试题

    try catch finally 执行顺序面试题总结 执行顺序 今天牛客网遇到这个题目,做对了,但是下面的评论却很值得看看 public class TestTry { public int add ...

  5. PromQL的简单使用

    PromQL的简单使用 一.背景 二.PromQL的数据类型 三.字面量 1.字符串字面量 2.浮点数字面量 四.时间序列选择器 1.即时向量选择器 1.组成部分 2.指标名称和匹配器的组合 3.匹配 ...

  6. FastAPI 学习之路(三十三)操作数据库

    通过创建pydantic模型进行验证提交数据 from pydantic import BaseModel class UserBase(BaseModel): email: str class Us ...

  7. 前端大牛带你了解JavaScript 函数式编程

    前言 函数式编程在前端已经成为了一个非常热门的话题.在最近几年里,我们看到非常多的应用程序代码库里大量使用着函数式编程思想. 本文将略去那些晦涩难懂的概念介绍,重点展示在 JavaScript 中到底 ...

  8. Linux上Qt旋转显示

    对于嵌入式设备来说用于显示的LCD总是千奇百怪,比如说明明是一个竖屏,但是客户却要当横屏使用,也就是意味着我们需要将整个屏幕上显示的内容旋转90度或者270度. 这个操作对于Android系统来说相当 ...

  9. Linux Ubuntu stty 使用

    stty(set tty)命令用于显示和修改当前注册的终端的属性. 该命令是一个用来改变并打印终端行设置的常用命令. stty -a #将所有选项设置的当前状态写到标准输出中 old_stty_set ...

  10. cf Inverse the Problem (最小生成树+DFS)

    题意: N个点.N行N列d[i][j]. d[i][j]:结点i到结点j的距离. 问这N个点是否可能是一棵树.是输出YES,否则输出NO. 思路: 假设这个完全图是由一棵树得来的,则我们对这个完全图求 ...