题解【[HNOI2010]弹飞绵羊】
\]
有 \(n\) 个弹力装置排成一排,第 \(i\) 个弹力装置的弹力系数是 \(k_i\) ,绵羊到第 \(i\) 个装置时,会被弹到第 \(i+k_i\) 个弹力装置,若第 \(i+k_i\) 个装置不存在,则绵羊被弹飞。
你要维护这 \(n\) 个弹力装置,支持 \(2\) 种操作:
1 x询问绵羊初始在第 \(x\) 个弹力装置时,被弹几次后被弹飞。2 x y将 \(k_x\) 改成 \(y\) 。
\]
我们把弹力装置抽象成一个点,弹力装置的这种位移操作抽象成一条边,即有 \(n\) 个点,第 \(i\) 个点向第 \(i+k_i\) 个点连一条边, 考虑到绵羊被弹飞的情况,我们新建一个虚拟节点 \(n+1\) ,若绵羊被第 \(i\) 个弹力装置弹飞(即 \(i+k_i>n\)),我们就使第 \(i\) 个点向第 \(n+1\) 点连一条边。
考虑到每个节点都向后连边,我们建出来的图定是一个森林。
对于查询操作,就是问第 \(x\) 个节点与第 \(n+1\) 个节点之间有几条边。
对于修改操作,就是删去 \(x\) 原来向后连的边,再使得 \(x\) 向后新连一条边。
发现需要动态维护森林,于是我们就可以用动态维护森林的利器:\(\mathsf{LCT}\) 。
对于查询操作,我们依次调用
Make_root(x),access(n + 1),splay(n + 1),就把 \(x\) 到 \(n+1\) 的路径分出来了,若在辅助树上维护个 \(size_i\)(子树大小),此时答案即为 \(size_{n+1}-1\) (边数 \(=\) 点数 \(-\) \(1\))。对于修改操作,我们调用
Cut(x, x + k[x] > n ? n + 1 : x + k[x]),表示把 \(x\) 原来连出去的边删掉,再调用k[x] = y修改 \(k_x\) 的值,再调用Link(x, x + k[x] > n ? n + 1 : x + k[x]),表示将 \(x\) 新连出去一条边。
\]
#include<cstdio>
#include<algorithm>
#define RI register int
using namespace std;
inline int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
}
const int N=1001000;
int n,m;
int fa[N],ch[N][2],k[N],size[N]; bool rev[N];
int len,que[N];
#define lc(x) ch[x][0]
#define rc(x) ch[x][1]
void upd(int x)
{
size[x]=size[lc(x)]+size[rc(x)]+1;
}
void spread(int x)
{
if(rev[x]==true)
{
std::swap(lc(x),rc(x));
rev[lc(x)]^=1;rev[rc(x)]^=1;
rev[x]=false;
}
}
int get(int x)
{
return rc(fa[x])==x;
}
int Is_root(int x)
{
return lc(fa[x])!=x&&rc(fa[x])!=x;
}
void rotate(int x)
{
int y=fa[x],z=fa[y],chk=get(x);
if(!Is_root(y))ch[z][ch[z][1]==y]=x;
ch[y][chk]=ch[x][chk^1];fa[ch[x][chk^1]]=y;
ch[x][chk^1]=y,fa[y]=x,fa[x]=z;
upd(y),upd(x);
}
void splay(int x)
{
que[len=1]=x;
for(RI p=x;!Is_root(p);p=fa[p])que[++len]=fa[p];
for(RI i=len;i>=1;i--)spread(que[i]);
for(;!Is_root(x);rotate(x))
if(!Is_root(fa[x]))rotate(get(x)==get(fa[x])?fa[x]:x);
}
void access(int x)
{
for(RI y=0;x;y=x,x=fa[x])
{
splay(x);
rc(x)=y,fa[y]=x;
upd(x);
}
}
int Find_root(int x)
{
access(x);
splay(x);
while(spread(x),lc(x))
x=lc(x);
splay(x);
return x;
}
void Make_root(int x)
{
access(x);
splay(x);
rev[x]^=1;
}
void Link(int x,int y)
{
if(Find_root(x)==Find_root(y))
return;
Make_root(x);
fa[x]=y;
}
void Cut(int x,int y)
{
Make_root(x);
access(y);
splay(y);
if(lc(y)!=x||lc(x)||rc(x))
return;
lc(y)=fa[x]=0;
upd(y);
}
int ask(int x,int y)
{
Make_root(x);
access(y);
splay(y);
return size[y];
}
int main()
{
n=read();
for(RI i=1;i<=n;i++)
k[i]=read();
for(RI i=1;i<=n;i++)
Link(i,i+k[i]>n?n+1:i+k[i]);
m=read();
while(m--)
{
int opt=read(),x=read()+1;
switch(opt)
{
case 1:{
printf("%d\n",ask(x,n+1)-1);
break;
}
case 2:{
Cut(x,x+k[x]>n?n+1:x+k[x]);
k[x]=read();
Link(x,x+k[x]>n?n+1:x+k[x]);
break;
}
}
}
return 0;
}
\]
题解【[HNOI2010]弹飞绵羊】的更多相关文章
- P3203 [HNOI2010]弹飞绵羊(LCT)
P3203 [HNOI2010]弹飞绵羊 LCT板子 用一个$p[i]$数组维护每个点指向的下个点. 每次修改时cut*1+link*1就解决了 被弹出界时新设一个点,权为0,作为终点表示出界点.其他 ...
- [HNOI2010] 弹飞绵羊 (分块)
[HNOI2010] 弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上 ...
- 洛谷 P3203 [HNOI2010]弹飞绵羊 解题报告
P3203 [HNOI2010]弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一 ...
- [BZOJ 2002] [HNOI2010]弹飞绵羊(Link Cut Tree)
[BZOJ 2002] [HNOI2010]弹飞绵羊(Link Cut Tree) 题面 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一 ...
- 「洛谷P3202」[HNOI2010]弹飞绵羊 解题报告
P3203 [HNOI2010]弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一 ...
- [Luogu P3203] [HNOI2010]弹飞绵羊 (LCT维护链的长度)
题面 传送门:洛谷 Solution 这题其实是有类似模型的. 我们先考虑不修改怎么写.考虑这样做:每个点向它跳到的点连一条边,最后肯定会连成一颗以n+1为根的树(我们拿n+1代表被弹出去了).题目所 ...
- P3203 [HNOI2010]弹飞绵羊 —— 懒标记?分块?LCT?...FAQ orz
好久没写博客了哈,今天来水一篇._(:з」∠)_ 题目 :弹飞绵羊(一道省选题) 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏 ...
- P3203 [HNOI2010]弹飞绵羊 —— 懒标记?分块?
好久没写博客了哈,今天来水一篇._(:з」∠)_ 题目 :弹飞绵羊(一道省选题) 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏 ...
- 洛谷P3203 [HNOI2010] 弹飞绵羊 [LCT]
题目传送门 弹飞绵羊 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置, ...
- P3203 [HNOI2010]弹飞绵羊(LCT)
弹飞绵羊 题目传送门 解题思路 LCT. 将每个节点的权值设为\(1\),连接\(i\)和\(i+ki\),被弹飞就连上\(n\),维护权值和\(sum[]\).从\(j\)弹飞需要的次数就是\(sp ...
随机推荐
- laravel配置加解密
基于安全考虑,我们php项目配置文件中密码应该是加密的,laravel中也提供了OpenSSL 的 AES-256-CBC 来进行加密 但是如果我们项目配置的是其他加密方式,且希望以最少的改动实现读取 ...
- K8S基于ingress-nginx实现灰度发布
之前介绍过使用ambassador实现灰度发布,今天介绍如何使用ingre-nginx实现. 介绍 Ingress-Nginx 是一个K8S ingress工具,支持配置 Ingress Annota ...
- P1850 换教室 期望dp
P1850 换教室 题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有 2n2n 节课程安排在 nn 个时间段上.在第 ii(1 \leq ...
- 【C_Language】---队列和栈的C程序实现
这几天总结了C语言的队列,栈的实现方法,在此总结一下:一.栈 首先从栈开始,诚然,相信学习过数据结构的你,肯定应该知道栈是什么东西了,如果不知道也没事每一句话我就可以帮你总结--数据只在栈顶进行插入和 ...
- 初识runtime
首先需要加上头文件#import<objc/runtime.h>和#Import<objc/message.h> 将A中的某个方法替换成B中某个方法,且没有任何的耦合 这里 ...
- 官方文档中文版!Spring Cloud Stream 快速入门
本文内容翻译自官方文档,spring-cloud-stream docs,对 Spring Cloud Stream的应用入门介绍. 一.Spring Cloud Stream 简介 官方定义 Spr ...
- shell 条件测试
1.文件相关 -e 判断文件或者文件夹是否存在 -d 判断目录是否存在 -f 判断文件是否存在 -r 判断是否有读权限 -w 判断是否有写权限 -x 判断是否有执行权限 1.1命令行使用 [root@ ...
- synchronized的使用
概念: 是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操 ...
- [ZJOI2006]书架(权值splay)
[ZJOI2006]书架(luogu) Description 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看 ...
- Spring框架学习笔记(8)——spring boot+mybatis plus+mysql项目环境搭建
之前写的那篇Spring框架学习笔记(5)--Spring Boot创建与使用,发现有多小细节没有提及,,正好现在又学习了mybatis plus这款框架,打算重新整理一遍,并将细节说清楚 1.通过I ...