刷题总结——弹飞绵羊(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]]即为答 ...
 
随机推荐
- ajax报错问题的解决
			
背景:用ajax与服务器页面进行交互 问题:XMLHttpRequest.status==0并且XMLHttpRequest.readyState==0并且textStatus==error 关于XM ...
 - Cordova插件中JavaScript代码与Java的交互细节介绍
			
在Cordova官网中有这么一张架构图:大家看右下角蓝色的矩形框"Custom Plugin"--自定义插件.意思就是如果您用Cordova打包Mobile应用时,发现您的移动应用 ...
 - JS常用操作节点的方法
			
js常见的创建dom节点的方法有 createElement() 创建一个元素节点 => 接收参数为string类型的nodename createTextNode() 创建一个文本节点 =&g ...
 - ssh的server安装和安装指定版本的软件的方法
			
ssh程序分为有客户端程序openssh-client和服务端程序openssh-server.如果需要ssh登陆到别的电脑,需要安装openssh-client,该程序ubuntu是默认安装的.而如 ...
 - objdump命令
			
0x00 objdump命令是Linux下的反汇编目标文件或者可执行文件的命令 0x01 objdump -f 显示test的文件头信息 $ objdump -f levellevel: file ...
 - shell脚本,一个字符一个字符输出。
			
[root@localhost wyb]# cat file abc def abc 789de f567 [root@localhost wyb]# cat fffile.sh #!/bin/bas ...
 - js函数式编程(三)-compose和pointFree
			
compose即函数嵌套组合 组合compose在第一篇已经初见端倪,可以感受一下.compose函数的实现用闭包的方法.不完善实现如下: const compose = (f, g) => { ...
 - DOM事件总结
			
1.DOM事件: DOM0: element.onclick=function(){} DOM2: element.addEventListener(‘click’,function(){}) add ...
 - Java--容器/集合类(Collection)理解和使用
			
.数组和集合的比较 数组:长度固定,用来存放基本类型的数据 集合:长度不固定,用来存放对象的引用 二.集合类的基本概念 1.java.util包中提供了一些集合类,这些集合类也被称为容器. 常用的集合 ...
 - NOIP 成绩
			
这道题中点是在小数上,因为成绩可能是:“95.5 87.7……”所以我们就要用:printf和scanf这样就可以控制小数了!!! code: #include<bits/stdc++.h> ...