[HNOI2010][BZOJ2002] 弹飞绵羊 - LCT
Posted nishikino-curtis
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HNOI2010][BZOJ2002] 弹飞绵羊 - LCT相关的知识,希望对你有一定的参考价值。
Description
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
Input & Output
Input
第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1。
接下来一行有n个正整数,依次为那n个装置的初始弹力系数。
第三行有一个正整数m,
接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。
Output
对于每个i=1的情况,你都要输出一个需要的步数,占一行。
Sample
Input
4
1 2 1 1
3
1 1
2 1 1
1 1
Output
2
3
Solution
裸LCT,似乎分块可做?蒟蒻表示没想出来……首先如何表示被弹飞,在n之外开一个点即可,比如n+1,如果i + k_i > n,那么就link一下这两个点,需要注意的是cut同理。
为了方便操作,把标号统一+1s,各种姿势都会比较方便。查询的时候就split(x, n + 1),这样查询的区间大小实际上就是从x到n+1经过的点数,答案就是size[n + 1] - 1。
Code:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cctype>
using std::min;
using std::max;
using std::swap;
using std::isdigit;
const int maxn = 200005;
struct NODE
{
int siz, rev, c[2];
NODE()
{
siz = rev = c[2] = 0;
}
}t[maxn];
int n,m,k[maxn],f[maxn];
int opt,x,y;
inline int rd()
{
int x = 0;char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x;
}
void pushdown(int x)
{
if(t[x].rev && x)
{
t[t[x].c[0]].rev ^= 1;
t[t[x].c[1]].rev ^= 1;
swap(t[x].c[0], t[x].c[1]);
t[x].rev = 0;
}
}
void pushup(int x)
{
t[x].siz = t[t[x].c[0]].siz + t[t[x].c[1]].siz + 1;
}
int getid(int x)
{
return t[f[x]].c[1] == x;
}
int isroot(int x)
{
return t[f[x]].c[1] != x && t[f[x]].c[0] != x;
}
void rotate(int x)
{
int fa = f[x], fa_ = f[fa], k = getid(x);
if(!isroot(fa))
t[fa_].c[t[fa_].c[1] == fa] = x;
t[fa].c[k] = t[x].c[k ^ 1]; f[t[fa].c[k]] = fa;
t[x].c[k ^ 1] = fa;
f[fa] = x; f[x] = fa_;
pushup(fa); pushup(x);
}
void pushpath(int x)
{
if(!isroot(x)) pushpath(f[x]);
pushdown(x);
}
void splay(int x)
{
pushpath(x);
for(int fa; !isroot(x); rotate(x))
{
if(!isroot(fa = f[x]))
rotate(getid(x) == getid(fa) ? fa : x);
pushup(x);
}
}
void access(int x)
{
for(int y = 0; x; y = x, x = f[x])
splay(x), t[x].c[1] = y, pushup(x);
}
void makeroot(int x)
{
access(x); splay(x); t[x].rev ^= 1;
}
int findroot(int x)
{
access(x); splay(x);
while(t[x].c[0]) x = t[x].c[0];
return x;
}
void split(int x,int y)
{
makeroot(x); access(y); splay(y);
}
void link(int x,int y)
{
makeroot(x);
if(findroot(y) != x) f[x] = y;
}
void cut(int x,int y)
{
split(x, y); t[y].c[0] = f[x] = 0; pushup(y);
}
int main()
{
n = rd();
for(int i = 1; i <= n; ++i)
{
k[i] = rd();
if(i + k[i] > n) link(i, n + 1);
else link(i, i + k[i]);
}
m = rd();
for(int i = 1; i <= m; ++i)
{
opt = rd();
if(opt == 1)
{
x = rd();
x += 1;
split(x, n + 1);
printf("%d\n",t[n + 1].siz - 1);
}
else
{
x = rd(); y = rd();
x += 1;
if(x + k[x] > n)cut(x, n + 1);
else cut(x, x + k[x]);
k[x] = y;
if(x + k[x] > n)link(x, n + 1);
else link(x, x + k[x]);
}
}
return 0;
}
以上是关于[HNOI2010][BZOJ2002] 弹飞绵羊 - LCT的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ2002: [Hnoi2010]Bounce 弹飞绵羊
[bzoj2002][Hnoi2010]Bounce弹飞绵羊_LCT