\[\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. 抽象工厂模式(C++)

    #include <iostream> using namespace std; class Fruit { public: ; }; class AbstractFactory { pu ...

  2. 你还不会Git?那就不要写代码了(一)

    Git应用开发学习 如果你还不会使用Git,那就不要写代码了. 一旦你会使用了Git,就再也不想使用SVN了.永远也回不去了. Mac上使用Git,肯定离不开对Mac上的操作.就要使用常用的Linux ...

  3. Spring Boot2 系列教程 (二) | 第一个 SpringBoot 工程详解

    微信公众号:一个优秀的废人 如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 哎呦喂,按照以往的惯例今天周六我的安排应该是待在家学学猫叫啥的.但是今年这种日子就可能一去不复返了,没法办法啊.前 ...

  4. java jvm jre jdk三者的关系

    jvm:java虚拟机器(跨平台的关键) jre:java运行环境 jdk:java 开发工具包(kit) jdk>jre>jvm 环境变量配置 https://www.cnblogs.c ...

  5. github 删除库

    1.查看库 2.选择想要删除的库,点击setting 3.删除库

  6. 1.HelloWorld 仪式感

    HelloWorld: 1.随便新建一个文件夹,存放代码. 2.新建一个java文件 文件后缀改为 .java Hello.java 系统可能没显示文件后缀名,我们需要手动打开 3.编写代码 publ ...

  7. 认识一下 RabbitMQ

    分布式系统中,如何在各个应用之间高效的进行通信,是系统设计中的一个关键. 使用 消息代理(message broker) 是一个优雅的解决方案. RabbitMQ 就是一个被广泛应用的消息代理,遵循 ...

  8. Java入门 - 语言基础 - 14.String类

    原文地址:http://www.work100.net/training/java-string.html 更多教程:光束云 - 免费课程 String类 序号 文内章节 视频 1 概述 2 创建字符 ...

  9. 【Java并发基础】Java线程的生命周期

    前言 线程是操作系统中的一个概念,支持多线程的语言都是对OS中的线程进行了封装.要学好线程,就要搞清除它的生命周期,也就是生命周期各个节点的状态转换机制.不同的开发语言对操作系统中的线程进行了不同的封 ...

  10. BZOJ 3691 游行

    题目传送门 分析: 没被访问的点要C费用,跑一次路要C费用 把这两个统一一下试试... 那就是每次不标记起点或者终点 那就是路径覆盖了2333 二分图,x 部 i 号点与 y 部 j 号点连 i 到 ...