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

原文地址:https://www.cnblogs.com/nishikino-curtis/p/9047522.html

时间: 2024-10-25 21:23:47

[HNOI2010][BZOJ2002] 弹飞绵羊 - LCT的相关文章

BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊( LCT )

LCT... ---------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; ++i ) #define clr( x , c ) memset( x

bzoj2002 弹飞绵羊 LCT

2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 6706  Solved: 3522[Submit][Status][Discuss] Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki

[BZOJ2002][Hnoi2010]Bounce弹飞绵羊 LCT

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2002 建图,每次往后面跳就往目标位置连边,将跳出界的点设为同一个点.对于修改操作发现可以用LCT维护图的连通性,然后用size域维护跳的点的次数就行了. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int inline readint(

BZOJ2002: [Hnoi2010]Bounce 弹飞绵羊 LCT

这道题的lct不想说什么...... 这道题是lct的假板子题你需要精简并适当改进LCT给他加上不清真的属性...... #include<cstdio> #include<cstring> #define MAXN 200010 using namespace std; struct spaly { spaly *ch[2],*f; int size; void pushup() { size=ch[1]->size+ch[0]->size+1; } }null[MA

【bzoj2002】[Hnoi2010]Bounce 弹飞绵羊 分块

[bzoj2002][Hnoi2010]Bounce 弹飞绵羊 2014年7月30日8101 Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞.绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞.为了使得游戏更有趣,Los

【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]]即为答案 更改时,cut(x,next[x]) link(x,min(x+k,n+1)) 记得splay旋转后要更新size 1 #include<bits/stdc++.h> 2 #define N 200005 3 using namespace std; 4 int read(){ 5 int x

【BZOJ】2002: [Hnoi2010]Bounce 弹飞绵羊(lct)

(BZOJ挂了,还没在BZOJ测,先是在wikioi测过了,,) 囧.在军训时立志要学lct!!!这是一道lct的裸题,只有access操作(10行都没有啊亲...缩行大法的话,我就不说了..)(link操作相当于水过),其实lct很简单..想想都有点小激动...... lct用splay维护的话,一下就写好了..但是我在写lct的时候,发现了一些我原来splay的老问题,我原来也知道了的,就是将null的ch给赋值了,因为在rot操作里没有特判,所以导致了null的孩子被赋值了,导致我的lct

bzoj 2002 : [Hnoi2010]Bounce 弹飞绵羊 (LCT)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2002 题面: 2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 15763  Solved: 8080[Submit][Status][Discuss] Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开

BZOJ 题目2002: [Hnoi2010]Bounce 弹飞绵羊(link cut tree)

2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 5421  Solved: 2863 [Submit][Status][Discuss] Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹