Evanyou Blog 彩带

洛谷P3203 [HNOI2010] 弹飞绵羊 [LCT]

  题目传送门

弹飞绵羊

题目描述

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

输入输出格式

输入格式:

 

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1。

接下来一行有n个正整数,依次为那n个装置的初始弹力系数。

第三行有一个正整数m,

接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。

 

输出格式:

 

对于每个i=1的情况,你都要输出一个需要的步数,占一行。

 

输入输出样例

输入样例#1: 
4
1 2 1 1
3
1 1
2 1 1
1 1
输出样例#1: 
2
3

说明

对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

 


  分析:

  把每个装置看作一个点,然后连边,每次修改弹力值就可以看作断边和连边,可以用LCT维护。那么查询显然就直接求该点原树到根节点的距离。维护的时候比较方便,很多函数都可以省略。

  Code:

 

//It is made by HolseLee on 30th June 2018
//Luogu.org P3203
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int n,m,a[N],fa[N],s[N],ch[N][2];
inline int read()
{
    char ch=getchar();int num=0;bool flag=false;
    while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
    while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
    return flag?-num:num;
}
inline void pushup(int x)
{
    s[x]=s[ch[x][0]]+s[ch[x][1]]+1;
}
inline bool isroot(int x)
{
    return (ch[fa[x]][0]!=x)&&(ch[fa[x]][1]!=x);
}
inline void rotate(int x)
{
    int y=fa[x],z=fa[y];    
    int k=(ch[y][1]==x);
    int w=ch[x][k^1];
    if(!isroot(y))ch[z][ch[z][1]==y]=x;
    ch[x][k^1]=y;ch[y][k]=w;
    if(w)fa[w]=y;fa[y]=x;fa[x]=z;
    pushup(y);
}
inline void splay(int x)
{
    while(!isroot(x)){
        int y=fa[x],z=fa[y];
        if(!isroot(y))
        ((ch[y][0]==x)^(ch[z][0]==y))?
        rotate(y):rotate(x);
        rotate(x);}
    pushup(x);
}
inline void access(int x)
{
    for(int y=0;x;x=fa[y=x])
    splay(x),ch[x][1]=y,pushup(x);
}
int main()
{
    n=read();int x,y,z;
    for(int i=1;i<=n;i++){
        s[i]=1;x=read();
        if(i+x<=n)fa[i]=i+x;}
    m=read();
    for(int i=1;i<=m;i++){
        x=read();y=read();
        if(x==1){
            ++y;
            access(y);splay(y);
            printf("%d\n",s[y]);
        }
        else{
            z=read();++y;
            access(y);splay(y);
            ch[y][0]=fa[ch[y][0]]=0;
            if(y+z<=n)fa[y]=y+z;
            pushup(y);}
    }
    return 0;
}

 

posted @ 2018-06-30 16:23  HolseLee  阅读(194)  评论(0编辑  收藏  举报