[HNOI2010]弹飞绵羊 (平衡树,LCT动态树)
题面
题解
因为每个点都只能向后跳到一个唯一的点,但可能不止一个点能跳到后面的某个相同的点,
所以我们把它抽象成一个森林。(思考:为什么是森林而不是树?)
子节点可以跳到父节点,根节点再跳就跳飞了。
由于我们发现有一些父子关系要变,所以不能用树链剖分等静态的数据结构,可以用LCT(Link-Cut-Tree 联-切-树,即动态树,支持动态修改父子关系)。
但是当我们询问答案的时候,我们发现wa了,那是因为我们询问的是x点到根的路径上的点数,但是各种LCT操作已经把原先的根不知换到那里去了,所以整个过程中,我们要维护树的根不变。
这个其实很简单,每次进行涉及换根操作时,我们都把原先的根存一下(Findroot()/Find()),操作完后,再把根换回去(Makeroot()),全过程中,当发现x + kx大于n时,就Makeroot(x)。
(由于是道数据结构题,题解写得真的不是很长,请尽量理解吧)
CODE
LCT建议压行,不仅好改而且好看。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<algorithm>
#include<map>
#include<stack>
#define LL long long
#define MAXN 2000050
#define DB double
#define lowbit(x) ((-x & x))
#define rg register
using namespace std;
inline LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
return x * f;
}
int n;
int m,i,j,s,o,k;
//--------------------------key numbers-------------------------------
struct tr{
int s[2],fa;
int siz;
int nm,as;
int lzn,lzr;// lzn其实不需要,只是懒得删
tr(){s[0] = s[1] = 0;nm = 0;siz = 0;lzn = lzr = 0;as = 0;}
}tre[MAXN];int cnt_splay = 0,st[MAXN],sttop = 0;
inline int newnode(int nm) {
int ct = ++cnt_splay;
tre[ct] = tr();
tre[ct].nm = nm;
tre[ct].as = nm;
tre[ct].siz = 1;
return ct;
}
inline bool isroot(int x) {
if(tre[tre[x].fa].s[1] == x || tre[tre[x].fa].s[0] == x) return 0;
return 1;
}
inline void update(int x) {
int l=tre[x].s[0],r = tre[x].s[1];tre[0] = tr();
tre[x].as = tre[x].nm + tre[l].as + tre[r].as;
tre[x].siz = tre[l].siz + tre[r].siz + 1;
tre[l].fa = x;tre[r].fa = x;tre[0] = tr();
}
inline void changer(int x) {swap(tre[x].s[0],tre[x].s[1]); tre[x].lzr ^= 1;}
inline void pushdown(int x) {
if(!x) return ;
if(tre[x].lzr) {
changer(tre[x].s[0]);
changer(tre[x].s[1]);
tre[x].lzr = 0;
}return ;
}
inline void pushup(int x) {
sttop = 0;st[++sttop] = x;
for(int f = x;!isroot(f); f = tre[f].fa) st[++sttop] = tre[f].fa;
while(sttop) pushdown(st[sttop --]);
}
inline void rotate(int x) {
int y = tre[x].fa,z = tre[y].fa;
int d = (tre[y].s[1] == x);
if(!isroot(y)) tre[z].s[tre[z].s[1] == y] = x;
tre[x].fa = z;
tre[y].s[d] = tre[x].s[d^1];
if(tre[y].s[d]) tre[tre[y].s[d]].fa = y;
tre[x].s[d^1] = y;
tre[y].fa = x;
update(y);update(x);
}
inline void splay(int x) {
pushup(x);
while(!isroot(x)) {
int y = tre[x].fa,z = tre[y].fa;
if(!isroot(y)) {
if((tre[y].s[1] == x) ^ (tre[z].s[1] == y)) rotate(x);
else rotate(y);
}
rotate(x);
}
update(x); return ;
}
inline void wash() {splay(rand() % cnt_splay + 1);}
//--------------------------splay-------------------------------------
inline void Access(int x) {
for(int pre = 0; x; pre = x,x = tre[x].fa) {
splay(x);
tre[x].s[1] = pre;
update(x);
}return ;
}
inline void Maketop(int x) {Access(x);splay(x);}
inline void Makeroot(int x) {Access(x); splay(x); changer(x);}
inline int Findroot(int x) {for(Maketop(x); tre[x].s[0]; x = tre[x].s[0]); splay(x); return x;}
inline void Change(int x,int nm) {Maketop(x); tre[x].nm = nm; update(x);}
//##### no Makeroot() inside
inline void Link(int x,int y) {Makeroot(x); tre[x].fa = y;}
inline void Cut(int x,int y) {Makeroot(x); Maketop(y); tre[y].s[0] = tre[x].fa = 0; update(y); pushup(x);}
inline int Getline(int x,int y) {Makeroot(x); Maketop(y); update(y); return y;}
inline bool Haveedge(int x,int y) {Makeroot(x); Maketop(y); return tre[x].fa == y;}
//-------------------------Link Cut Tree------------------------------
char ss[20];
int ki[MAXN];
int main() {
n = read();
cnt_splay = 0;
for(int i = 1;i <= n+3;i ++) {
newnode(1);
}
for(int i = 1;i <= n;i ++) {
ki[i] = read();
if(i + ki[i] <= n) Link(i,i + ki[i]);
else Makeroot(i);
}
m = read();
while(m --) {
k = read();
if(k == 1) {
s = read() + 1;
Access(s);
splay(s);
printf("%d\n",tre[s].as);
}
else if(k == 2) {
s = read() + 1;o = read();
if(s + ki[s] <= n) {
int v = s + ki[s];
int rt = Findroot(v);
Cut(s,v);
Makeroot(rt);
}
ki[s] = o;
if(s + ki[s] > n) Makeroot(s);
else {
int rt = Findroot(s + ki[s]);
Link(s,s + ki[s]);
Makeroot(rt);
}
}
}
return 0;
}
[HNOI2010]弹飞绵羊 (平衡树,LCT动态树)的更多相关文章
- P3203 [HNOI2010]弹飞绵羊(LCT)
P3203 [HNOI2010]弹飞绵羊 LCT板子 用一个$p[i]$数组维护每个点指向的下个点. 每次修改时cut*1+link*1就解决了 被弹出界时新设一个点,权为0,作为终点表示出界点.其他 ...
- BZOJ 2002 Bounce 弹飞绵羊 (分块或动态树)
2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 13768 Solved: 6989[Subm ...
- 洛谷P3203 [HNOI2010]弹飞绵羊(LCT,Splay)
洛谷题目传送门 关于LCT的问题详见我的LCT总结 思路分析 首先分析一下题意.对于每个弹力装置,有且仅有一个位置可以弹到.把这样的一种关系可以视作边. 然后,每个装置一定会往后弹,这不就代表不存在环 ...
- 2002. [HNOI2010]弹飞绵羊【LCT】
Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置 ...
- 【洛谷 P3203】 [HNOI2010]弹飞绵羊(LCT)
题目链接 把每个点和能跳到的点连边,于是就构成了一个森林. 查询操作就是该点到根的路径长度,修改操作就相当于删边再重新连边. 显然是\(LCT\)的强项. 查询时\(access(x),splay(x ...
- [Luogu P3203] [HNOI2010]弹飞绵羊 (LCT维护链的长度)
题面 传送门:洛谷 Solution 这题其实是有类似模型的. 我们先考虑不修改怎么写.考虑这样做:每个点向它跳到的点连一条边,最后肯定会连成一颗以n+1为根的树(我们拿n+1代表被弹出去了).题目所 ...
- 洛谷 P3203 [HNOI2010]弹飞绵羊 解题报告
P3203 [HNOI2010]弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一 ...
- [HNOI2010] 弹飞绵羊 (分块)
[HNOI2010] 弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上 ...
- [BZOJ 2002] [HNOI2010]弹飞绵羊(Link Cut Tree)
[BZOJ 2002] [HNOI2010]弹飞绵羊(Link Cut Tree) 题面 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一 ...
- 「洛谷P3202」[HNOI2010]弹飞绵羊 解题报告
P3203 [HNOI2010]弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一 ...
随机推荐
- camunda流程引擎概念术语
前言 本文重点介绍开源流程引擎camunda的核心概念,这些概念同样适用于JBMP.Activiti.Flowable流程引擎,了解这些基本概念和原理,使用流程引擎API将更得心应手. 一.Proce ...
- Python中的逻辑表达式
首先要明确一点,Python的逻辑运算符,可以用来操作任何类型的表达式(不局限于Bool类型),且运算后的结果也不一定是Bool类型的,而是其左右其中一个表达式的值 表达式1 and 表达式2 pyt ...
- HTML,CSS,JS,DOM,jQuery
HTML 超链接访问顺序 a:link-->a:visited-->a:hover-->a:active.(有顺序) link:表示从未访问过的链接的样式 visited:表示已经访 ...
- DAST 黑盒漏洞扫描器 第六篇:运营篇(终)
0X01 前言 转载请标明来源:https://www.cnblogs.com/huim/ 当项目功能逐渐成熟,同时需要实现的是运营流程和指标体系建设.需要工程化的功能逐渐少了,剩下的主要工作转变成持 ...
- Mybatis-Plus介绍
Mybatis-Plus介绍 Mybatis-Plus概念 Mybatis-Plus介绍 官网https://mybatis-plus/或https://mp.baomidou.com/ mybati ...
- NC14247 Xorto
NC14247 Xorto 题目 题目描述 给定一个长度为 \(n\) 的整数数组,问有多少对互不重叠的非空区间,使得两个区间内的数的异或和为 \(0\) . 输入描述 第一行一个数 \(n\) 表示 ...
- 链表设计与Java实现,手写LinkedList这也太清楚了吧!!!
链表设计与实现 在谈链表之前,我们先谈谈我们平常编程会遇到的很常见的一个问题.如果在编程的时候,某个变量在后续编程中仍需使用,我们可以用一个局部变量来保存该值,除此之外一个更加常用的方法就是使用容器了 ...
- 字节输入流_InputStream类&FileInputStream类介绍和字节输入流读取字节数据
java.io.InputStream:字节输入流 此抽象类是表示字节输入流的所有类的超类 定义了所有子类共性的方法: int read()从输入流中读取数据的下一个字节 int read(byte[ ...
- 【跟着大佬学JavaScript】之lodash防抖节流合并
前言 前面已经对防抖和节流有了介绍,这篇主要看lodash是如何将防抖和节流合并成一个函数的. 初衷是深入lodash,学习它内部的好代码并应用,同时也加深节流防抖的理解.这里会先从防抖开始一步步往后 ...
- PySide6/PyQt开发xml编辑器(1)
QTreeWidget折叠子项(折叠当前项的所有子项) 本文仅供本人知识总结使用,所以内容会比较浅显,不喜勿喷. 目录 QTreeWidget折叠子项(折叠当前项的所有子项) 目录 一.仅折叠子项 二 ...