\[\texttt{Description}
\]

有 \(n\) 个弹力装置排成一排,第 \(i\) 个弹力装置的弹力系数是 \(k_i\) ,绵羊到第 \(i\) 个装置时,会被弹到第 \(i+k_i\) 个弹力装置,若第 \(i+k_i\) 个装置不存在,则绵羊被弹飞。

你要维护这 \(n\) 个弹力装置,支持 \(2\) 种操作:

  • 1 x 询问绵羊初始在第 \(x\) 个弹力装置时,被弹几次后被弹飞。
  • 2 x y 将 \(k_x\) 改成 \(y\) 。

\[\texttt{Solution}
\]

  • 我们把弹力装置抽象成一个点,弹力装置的这种位移操作抽象成一条边,即有 \(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\) 新连出去一条边。

\[\texttt{Code}
\]

#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;
}

\[\texttt{Thanks} \ \texttt{for} \ \texttt{watching}
\]

题解【[HNOI2010]弹飞绵羊】的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. P3203 [HNOI2010]弹飞绵羊 —— 懒标记?分块?LCT?...FAQ orz

    好久没写博客了哈,今天来水一篇._(:з」∠)_ 题目 :弹飞绵羊(一道省选题) 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏 ...

  8. P3203 [HNOI2010]弹飞绵羊 —— 懒标记?分块?

    好久没写博客了哈,今天来水一篇._(:з」∠)_ 题目 :弹飞绵羊(一道省选题) 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏 ...

  9. 洛谷P3203 [HNOI2010] 弹飞绵羊 [LCT]

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

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

    弹飞绵羊 题目传送门 解题思路 LCT. 将每个节点的权值设为\(1\),连接\(i\)和\(i+ki\),被弹飞就连上\(n\),维护权值和\(sum[]\).从\(j\)弹飞需要的次数就是\(sp ...

随机推荐

  1. laravel配置加解密

    基于安全考虑,我们php项目配置文件中密码应该是加密的,laravel中也提供了OpenSSL 的 AES-256-CBC 来进行加密 但是如果我们项目配置的是其他加密方式,且希望以最少的改动实现读取 ...

  2. K8S基于ingress-nginx实现灰度发布

    之前介绍过使用ambassador实现灰度发布,今天介绍如何使用ingre-nginx实现. 介绍 Ingress-Nginx 是一个K8S ingress工具,支持配置 Ingress Annota ...

  3. P1850 换教室 期望dp

    P1850 换教室 题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有 2n2n 节课程安排在 nn 个时间段上.在第 ii(1 \leq ...

  4. 【C_Language】---队列和栈的C程序实现

    这几天总结了C语言的队列,栈的实现方法,在此总结一下:一.栈 首先从栈开始,诚然,相信学习过数据结构的你,肯定应该知道栈是什么东西了,如果不知道也没事每一句话我就可以帮你总结--数据只在栈顶进行插入和 ...

  5. 初识runtime

    首先需要加上头文件#import<objc/runtime.h>和#Import<objc/message.h>   将A中的某个方法替换成B中某个方法,且没有任何的耦合 这里 ...

  6. 官方文档中文版!Spring Cloud Stream 快速入门

    本文内容翻译自官方文档,spring-cloud-stream docs,对 Spring Cloud Stream的应用入门介绍. 一.Spring Cloud Stream 简介 官方定义 Spr ...

  7. shell 条件测试

    1.文件相关 -e 判断文件或者文件夹是否存在 -d 判断目录是否存在 -f 判断文件是否存在 -r 判断是否有读权限 -w 判断是否有写权限 -x 判断是否有执行权限 1.1命令行使用 [root@ ...

  8. synchronized的使用

    概念: 是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操 ...

  9. [ZJOI2006]书架(权值splay)

    [ZJOI2006]书架(luogu) Description 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看 ...

  10. Spring框架学习笔记(8)——spring boot+mybatis plus+mysql项目环境搭建

    之前写的那篇Spring框架学习笔记(5)--Spring Boot创建与使用,发现有多小细节没有提及,,正好现在又学习了mybatis plus这款框架,打算重新整理一遍,并将细节说清楚 1.通过I ...