题面

题解

因为每个点都只能向后跳到一个唯一的点,但可能不止一个点能跳到后面的某个相同的点,

所以我们把它抽象成一个森林。(思考:为什么是森林而不是树?)

子节点可以跳到父节点,根节点再跳就跳飞了。

由于我们发现有一些父子关系要变,所以不能用树链剖分等静态的数据结构,可以用LCT(Link-Cut-Tree 联-切-树,即动态树,支持动态修改父子关系)。

但是当我们询问答案的时候,我们发现wa了,那是因为我们询问的是x点到根的路径上的点数,但是各种LCT操作已经把原先的根不知换到那里去了,所以整个过程中,我们要维护树的根不变

这个其实很简单,每次进行涉及换根操作时,我们都把原先的根存一下(Findroot()/Find()),操作完后,再把根换回去(Makeroot()),全过程中,当发现x + kx大于n时,就Makeroot(x)。

(由于是道数据结构题,题解写得真的不是很长,请尽量理解吧)

CODE

LCT建议压行,不仅好改而且好看。

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<vector>
  5. #include<queue>
  6. #include<stack>
  7. #include<cmath>
  8. #include<algorithm>
  9. #include<map>
  10. #include<stack>
  11. #define LL long long
  12. #define MAXN 2000050
  13. #define DB double
  14. #define lowbit(x) ((-x & x))
  15. #define rg register
  16. using namespace std;
  17. inline LL read() {
  18. LL f = 1,x = 0;char s = getchar();
  19. while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
  20. while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
  21. return x * f;
  22. }
  23. int n;
  24. int m,i,j,s,o,k;
  25. //--------------------------key numbers-------------------------------
  26. struct tr{
  27. int s[2],fa;
  28. int siz;
  29. int nm,as;
  30. int lzn,lzr;// lzn其实不需要,只是懒得删
  31. tr(){s[0] = s[1] = 0;nm = 0;siz = 0;lzn = lzr = 0;as = 0;}
  32. }tre[MAXN];int cnt_splay = 0,st[MAXN],sttop = 0;
  33. inline int newnode(int nm) {
  34. int ct = ++cnt_splay;
  35. tre[ct] = tr();
  36. tre[ct].nm = nm;
  37. tre[ct].as = nm;
  38. tre[ct].siz = 1;
  39. return ct;
  40. }
  41. inline bool isroot(int x) {
  42. if(tre[tre[x].fa].s[1] == x || tre[tre[x].fa].s[0] == x) return 0;
  43. return 1;
  44. }
  45. inline void update(int x) {
  46. int l=tre[x].s[0],r = tre[x].s[1];tre[0] = tr();
  47. tre[x].as = tre[x].nm + tre[l].as + tre[r].as;
  48. tre[x].siz = tre[l].siz + tre[r].siz + 1;
  49. tre[l].fa = x;tre[r].fa = x;tre[0] = tr();
  50. }
  51. inline void changer(int x) {swap(tre[x].s[0],tre[x].s[1]); tre[x].lzr ^= 1;}
  52. inline void pushdown(int x) {
  53. if(!x) return ;
  54. if(tre[x].lzr) {
  55. changer(tre[x].s[0]);
  56. changer(tre[x].s[1]);
  57. tre[x].lzr = 0;
  58. }return ;
  59. }
  60. inline void pushup(int x) {
  61. sttop = 0;st[++sttop] = x;
  62. for(int f = x;!isroot(f); f = tre[f].fa) st[++sttop] = tre[f].fa;
  63. while(sttop) pushdown(st[sttop --]);
  64. }
  65. inline void rotate(int x) {
  66. int y = tre[x].fa,z = tre[y].fa;
  67. int d = (tre[y].s[1] == x);
  68. if(!isroot(y)) tre[z].s[tre[z].s[1] == y] = x;
  69. tre[x].fa = z;
  70. tre[y].s[d] = tre[x].s[d^1];
  71. if(tre[y].s[d]) tre[tre[y].s[d]].fa = y;
  72. tre[x].s[d^1] = y;
  73. tre[y].fa = x;
  74. update(y);update(x);
  75. }
  76. inline void splay(int x) {
  77. pushup(x);
  78. while(!isroot(x)) {
  79. int y = tre[x].fa,z = tre[y].fa;
  80. if(!isroot(y)) {
  81. if((tre[y].s[1] == x) ^ (tre[z].s[1] == y)) rotate(x);
  82. else rotate(y);
  83. }
  84. rotate(x);
  85. }
  86. update(x); return ;
  87. }
  88. inline void wash() {splay(rand() % cnt_splay + 1);}
  89. //--------------------------splay-------------------------------------
  90. inline void Access(int x) {
  91. for(int pre = 0; x; pre = x,x = tre[x].fa) {
  92. splay(x);
  93. tre[x].s[1] = pre;
  94. update(x);
  95. }return ;
  96. }
  97. inline void Maketop(int x) {Access(x);splay(x);}
  98. inline void Makeroot(int x) {Access(x); splay(x); changer(x);}
  99. inline int Findroot(int x) {for(Maketop(x); tre[x].s[0]; x = tre[x].s[0]); splay(x); return x;}
  100. inline void Change(int x,int nm) {Maketop(x); tre[x].nm = nm; update(x);}
  101. //##### no Makeroot() inside
  102. inline void Link(int x,int y) {Makeroot(x); tre[x].fa = y;}
  103. inline void Cut(int x,int y) {Makeroot(x); Maketop(y); tre[y].s[0] = tre[x].fa = 0; update(y); pushup(x);}
  104. inline int Getline(int x,int y) {Makeroot(x); Maketop(y); update(y); return y;}
  105. inline bool Haveedge(int x,int y) {Makeroot(x); Maketop(y); return tre[x].fa == y;}
  106. //-------------------------Link Cut Tree------------------------------
  107. char ss[20];
  108. int ki[MAXN];
  109. int main() {
  110. n = read();
  111. cnt_splay = 0;
  112. for(int i = 1;i <= n+3;i ++) {
  113. newnode(1);
  114. }
  115. for(int i = 1;i <= n;i ++) {
  116. ki[i] = read();
  117. if(i + ki[i] <= n) Link(i,i + ki[i]);
  118. else Makeroot(i);
  119. }
  120. m = read();
  121. while(m --) {
  122. k = read();
  123. if(k == 1) {
  124. s = read() + 1;
  125. Access(s);
  126. splay(s);
  127. printf("%d\n",tre[s].as);
  128. }
  129. else if(k == 2) {
  130. s = read() + 1;o = read();
  131. if(s + ki[s] <= n) {
  132. int v = s + ki[s];
  133. int rt = Findroot(v);
  134. Cut(s,v);
  135. Makeroot(rt);
  136. }
  137. ki[s] = o;
  138. if(s + ki[s] > n) Makeroot(s);
  139. else {
  140. int rt = Findroot(s + ki[s]);
  141. Link(s,s + ki[s]);
  142. Makeroot(rt);
  143. }
  144. }
  145. }
  146. return 0;
  147. }

[HNOI2010]弹飞绵羊 (平衡树,LCT动态树)的更多相关文章

  1. P3203 [HNOI2010]弹飞绵羊(LCT)

    P3203 [HNOI2010]弹飞绵羊 LCT板子 用一个$p[i]$数组维护每个点指向的下个点. 每次修改时cut*1+link*1就解决了 被弹出界时新设一个点,权为0,作为终点表示出界点.其他 ...

  2. BZOJ 2002 Bounce 弹飞绵羊 (分块或动态树)

    2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 13768  Solved: 6989[Subm ...

  3. 洛谷P3203 [HNOI2010]弹飞绵羊(LCT,Splay)

    洛谷题目传送门 关于LCT的问题详见我的LCT总结 思路分析 首先分析一下题意.对于每个弹力装置,有且仅有一个位置可以弹到.把这样的一种关系可以视作边. 然后,每个装置一定会往后弹,这不就代表不存在环 ...

  4. 2002. [HNOI2010]弹飞绵羊【LCT】

    Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置 ...

  5. 【洛谷 P3203】 [HNOI2010]弹飞绵羊(LCT)

    题目链接 把每个点和能跳到的点连边,于是就构成了一个森林. 查询操作就是该点到根的路径长度,修改操作就相当于删边再重新连边. 显然是\(LCT\)的强项. 查询时\(access(x),splay(x ...

  6. [Luogu P3203] [HNOI2010]弹飞绵羊 (LCT维护链的长度)

    题面 传送门:洛谷 Solution 这题其实是有类似模型的. 我们先考虑不修改怎么写.考虑这样做:每个点向它跳到的点连一条边,最后肯定会连成一颗以n+1为根的树(我们拿n+1代表被弹出去了).题目所 ...

  7. 洛谷 P3203 [HNOI2010]弹飞绵羊 解题报告

    P3203 [HNOI2010]弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一 ...

  8. [HNOI2010] 弹飞绵羊 (分块)

    [HNOI2010] 弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上 ...

  9. [BZOJ 2002] [HNOI2010]弹飞绵羊(Link Cut Tree)

    [BZOJ 2002] [HNOI2010]弹飞绵羊(Link Cut Tree) 题面 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一 ...

  10. 「洛谷P3202」[HNOI2010]弹飞绵羊 解题报告

    P3203 [HNOI2010]弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一 ...

随机推荐

  1. Acwing 1927 自动补全(知识点:hash,二分,排序)

    读完题目第一想法是trie树 ,不过好像没怎么做过trie树的题,看y总给的知识点是二分排序,所以就有了如下思路: 但是但是,看完其他题解之后才坚定了我的想法,原来真的是这样排序,暴力啊! 具体步骤 ...

  2. .NetCore实现图片缩放与裁剪 - 基于ImageSharp

    前言 (突然发现断更有段时间了 最近在做博客的时候,需要实现一个类似Lorempixel.LoremPicsum这样的随机图片功能,图片有了,还需要一个根据输入的宽度高度获取图片的功能,由于之前处理图 ...

  3. canal的使用

    一.简介 canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实 ...

  4. 【python基础】第05回 数据类型,交互,格式化输出,运算符

    上节内容回顾 1.python的注释 # 单行注释 pycharm快捷键:ctrl+? '''多行注释''' """多行注释""" 2.py ...

  5. OpenLayers入门(一)

    OpenLayers简介 OpenLayers(https://openlayers.org/)是一个用来帮助开发Web地图应用的高性能的.功能丰富的JavaScript类库,可以满足几乎所有的地图开 ...

  6. Linux 磁盘挂载和swap空间管理

    挂载:把指定的设备和根下面的某个文件夹建立关联 卸载:解除两者关系的过程 挂载文件系统:mount 格式:mount device mountpoint --- mount 设备名 挂载点 mount ...

  7. 图片64base转码与解码

    场景一:图片转码成base64,传输,接收后解码成png等格式图片 import base64 # 读取图片,转换为base64编码格式 with open("F:\Archer\pictu ...

  8. Android Studio 的初次使用

    记录我第一次使用Android Studio时遇到的问题以及一些简单的笔记. 我所使用的是Android Studio 2.2版本 遇到的问题 创建一个Hello World!项目无疑是相当简单的,我 ...

  9. vscode的安装、切换为中文简体、集成sass

    VScode设置中文 打开vscode ,按快捷键"Ctrl+Shift+P" 输入configure language,回车 选择安装其他语言 (默认是英文的) 选择简体中安装( ...

  10. 大家好,我是UCMP云管家,这是我的自我介绍

    随着云计算的不断普及,构建在计算.存储.网络.数据库等基础资源之上的云平台逐渐大行其道:而随着多种云平台技术路线的发展成熟,多个云厂商的云平台开始出现在企业IT市场.对于企业而言,为满足成本.按需.隐 ...