刷题总结——弹飞绵羊(bzoj2002)
题目:
Description
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
Input
第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000
Output
对于每个i=1的情况,你都要输出一个需要的步数,占一行。
Sample Input
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
3
题解:
算法1:引用洛谷官网题解:
LCT裸题。
首先,建立一个虚拟节点n+1n+1,绵羊到达这个节点即被弹飞。
对于每个装置,
如果i+Ki<=ni+Ki<=n,则执行Link(i,i+Ki)Link(i,i+Ki),否则Link(i,n+1)Link(i,n+1)。
对于修改操作,先执行Cut(j,j+Kj)Cut(j,j+Kj)(如果j+Kj>nj+Kj>n则为n+1n+1),再执行Link(j,j+k)Link(j,j+k)(如果j+k>nj+k>n则为n+1n+1),
并把KjKj赋为kk。
对于询问操作,分别执行MakeRoot(y)MakeRoot(y),Access(n+1)Access(n+1)和Splay(n+1)Splay(n+1),最终答案即为size[n+1]-1size[n+1]−1。
其中size[i]size[i]表示平衡树中节点ii的子树的大小。
表示第一次做的时候智障了····忘记拿n+1作为整棵树的根节点从而不知道怎么求深度···哎··
另外注意update
算法2:分块算法
这道题用分块算法简单得多···而且时间还要快一点
先分块,用pos[i]维护i会跳到块外的哪一点上,用times[i]维护i跳到块外的对应点上需要多少步,每次询问的时候一边跳pos[i]一边往ans加time[i]就可以了,复杂度为√n
对于修改直接修改这个点到所在块的初始点内的pos和time,复杂度同样为√n;
代码:
1.LCT
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=2e5+;
int tag[N],father[N],size[N],son[N][],stack[N],cnt,to[N];
int n,m,a,b,c;
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f;
}
inline void update(int now)
{
if(now)
{
size[now]=;
if(son[now][]) size[now]+=size[son[now][]];
if(son[now][]) size[now]+=size[son[now][]];
}
}
inline int get(int now)
{
return son[father[now]][]==now;
}
inline void pushdown(int now)
{
if(tag[now]&&now)
{
swap(son[now][],son[now][]);
tag[son[now][]]^=;
tag[son[now][]]^=;
tag[now]=;
}
}
inline bool isroot(int now)
{
if(!father[now]) return true;
else if(son[father[now]][]!=now&&son[father[now]][]!=now) return true;
else return false;
}
inline void rotate(int now)
{
pushdown(father[now]),pushdown(now);
int fa=father[now],ofa=father[fa],which=get(now);
if(!isroot(fa)&&ofa) son[ofa][son[ofa][]==fa]=now;
son[fa][which]=son[now][which^],father[son[fa][which]]=fa;
son[now][which^]=fa,father[fa]=now,father[now]=ofa;
update(fa),update(now);
}
inline void splay(int now)
{
stack[cnt=]=now;
for(int i=now;!isroot(i);i=father[i])
stack[++cnt]=father[i];
for(int i=cnt;i>=;i--)
pushdown(stack[i]);
while(!isroot(now))
{
if(!isroot(father[now]))
rotate(get(father[now])==get(now)?father[now]:now);
rotate(now);
}
}
inline void access(int now)
{
int temp=;
for(;now;temp=now,now=father[now])
{
splay(now),son[now][]=temp;
update(now);
}
}
inline void makeroot(int now)
{
access(now);splay(now);tag[now]^=;
}
inline void link(int a,int b)
{
makeroot(a);father[a]=b;
}
inline void cut(int a,int b)
{
makeroot(a);access(b);splay(b);
father[a]=son[b][]=;
}
inline int getans(int now)
{
makeroot(now);
access(n+);splay(n+);
return size[n+]-;
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=R();
for(int i=;i<=n+;i++)
size[i]=;
for(int i=;i<=n;i++)
{
a=R();
if(a+i<=n&&a!=)
{
to[i]=i+a;
link(i,a+i);
}
else if(a+i>n&&a!=)
{
to[i]=n+;
link(i,n+);
}
}
m=R();
while(m--)
{
a=R(),b=R();
if(a==)
{
int ans=getans(b+);
printf("%d\n",ans);
}
else
{
c=R();cut(b+,to[b+]);
if(b++c<=n&&c!=)
to[b+]=b++c,link(b+,b++c);
else if(b++c>n&&c!=)
to[b+]=n+,link(b+,n+);
}
}
return ;
}
2.分块
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=2e5+;
int n,m,times[N],pos[N],a[N],Right[N],Left[N],id[N],s,tots;
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f;
}
int main()
{
//freopen("a.in","r",stdin);
n=R();s=(int)sqrt(n);
for(int i=;i<=n;i++)
{
if(i%s==) id[i]=tots,Right[tots]=i;
else if(i%s==) id[i]=++tots,Left[tots]=i;
else id[i]=tots;
}
for(int i=;i<=n;i++) a[i]=R();
for(int i=n;i>=;i--)
{
int temp=a[i]+i;
if(temp>=n+)
pos[i]=-,times[i]=;
else if(temp<=Right[id[i]])
pos[i]=pos[temp],times[i]=times[temp]+;
else
pos[i]=temp,times[i]=;
}
m=R();int q,x,y;
while(m--)
{
q=R();
if(q==)
{
x=R();int ans=;
for(int i=x+;i!=-;i=pos[i])
ans+=times[i];
printf("%d\n",ans);
}
else
{
x=R(),y=R();
a[x+]=y;
for(int i=x+;i>=Left[id[x]];i--)
{
int temp=i+a[i];
if(temp>=n+) pos[i]=-,times[i]=;
else if(temp<=Right[id[i]])
pos[i]=pos[temp],times[i]=times[temp]+;
else
pos[i]=temp,times[i]=;
}
}
}
return ;
}
刷题总结——弹飞绵羊(bzoj2002)的更多相关文章
- 洛谷 P3203 [HNOI2010]弹飞绵羊 || bzoj2002
看来这个lct板子的确没什么问题 好像还可以分块做 #include<cstdio> #include<algorithm> using namespace std; type ...
- [bzoj2002][Hnoi2010]Bounce弹飞绵羊_LCT
Bounce弹飞绵羊 bzoj-2002 Hnoi-2010 题目大意:n个格子,每一个格子有一个弹簧,第i个格子会将经过的绵羊往后弹k[i]个,达到i+k[i].如果i+k[i]不存在,就表示这只绵 ...
- 【BZOJ2002】弹飞绵羊(Link-Cut Tree)
[BZOJ2002]弹飞绵羊(Link-Cut Tree) 题面 题目描述 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lost ...
- 【BZOJ2002】 [Hnoi2010]Bounce 弹飞绵羊
BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊 Solution 很早以前写的一道分块题,最近在搞LCT,又做了一遍. 1.LCT做法 看到这种动态修改,想下LCT怎么维护. 修改操作就 ...
- 【bzoj2002】[Hnoi2010]Bounce 弹飞绵羊 分块
[bzoj2002][Hnoi2010]Bounce 弹飞绵羊 2014年7月30日8101 Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀 ...
- BZOJ2002 Hnoi2010 Bounce 弹飞绵羊 【LCT】【分块】
BZOJ2002 Hnoi2010 Bounce 弹飞绵羊 Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始, ...
- 【codevs2333】&【BZOJ2002】弹飞绵羊[HNOI2010](分块)
我其实是在codevs上看到它的题号后才去做这道题的...2333... 题目传送门:codevs:http://codevs.cn/problem/2333/ bzoj:http://www.lyd ...
- [BZOJ2002][洛谷P3203][Hnoi2010]Bounce 弹飞绵羊(LCT维护链长)
luogu传送门 2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 16082 Solved: ...
- 【bzoj2002】[Hnoi2010]Bounce 弹飞绵羊 link-cut-tree
2016-05-30 11:51:59 用一个next数组,记录点x的下一个点是哪个 查询时,moveroot(n+1),access(x),splay(x) ,输出size[ch[x][0]]即为答 ...
随机推荐
- 使用 Cosmos DB 创建和查询 NoSQL 表
本教程演示如何使用 Azure 门户创建 Azure Cosmos DB 帐户,然后使用 DocumentDB .NET API 创建具有分区键的文档数据库和集合.通过在创建集合时定义分区键,应用程序 ...
- SQL Server中变量的声明和使用方法
声明局部变量语法:DECLARE @variable_name DataType其中 variable_name为局部变量的名称,DataType为数据类型.给局部变量赋值有两种方法:1.SET @v ...
- 洛谷 1164 小A点菜
题目背景 uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种. uim指着墙上的价目表(太低级了没有菜单),说:“随便点”. 题目描述 不过uim由于买了一些辅(e ...
- Ubuntu16.04下使用sublime text3搭建Python IDE
本来是想用pycharm,但你看它的内存要求,我的虚拟机一共也就1G Vim太别扭了,就算有代码颜色,不能自动对齐,不能规范格式,跳转到函数定义,显示文档,要配置起来太费劲,所以就尝试着用sublim ...
- Android(java)学习笔记143:Android中View动画之 XML实现 和 代码实现
1.Animation 动画类型 Android的animation由四种类型组成: XML中: alph 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动 ...
- eclipse中Lombok注解无效
问题现象:eclipse中使用lombok的@Date,引用get方法时,报错. 解决方案: 在lombok官网(https://www.projectlombok.org/download)下载,或 ...
- Spring @Transactional at interface
java - Where should I put @Transactional annotation: at an interface definition or at an implementin ...
- Python 输入输出 数据类型 变量
python输入输出 数据类型 变量 输入输出 print()在Python3中是函数 >>>print('hello world') #print注意print前面不要有任何空格 ...
- CPP-基础:关于多态
类的多态特性是支持面向对象的语言最主要的特性,有过非面向对象语言开发经历的人,通常对这一章节的内容会觉得不习惯,因为很多人错误的认为,支持类的封装的语言就是支持面向对象的,其实不然,Visua ...
- 关于HTML设置访问密码。
如果你要设置访问密码恐怕要使用sublime_text了 废话不多,开始!!! 先把这些东西加上: <html> <script> 然后开始写代码: 先辨别密码登录正确的情况: ...