1. 程式人生 > >洛谷P3203 [HNOI2010]彈飛綿羊

洛谷P3203 [HNOI2010]彈飛綿羊

hup pda pre std 輸入格式 find amp print spl

洛谷P3203 [HNOI2010]彈飛綿羊

題目描述

某天,Lostmonkey發明了一種超級彈力裝置,為了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。遊戲一開始,Lostmonkey在地上沿著一條直線擺上\(n\)個裝置,每個裝置設定初始彈力系數\(k_i\),當綿羊達到第i個裝置時,它會往後彈\(k_i\)步,達到第\(i+k_i\)個裝置,若不存在第\(i+k_i\)個裝置,則綿羊被彈飛。綿羊想知道當它從第\(i\)個裝置起步時,被彈幾次後會被彈飛。為了使得遊戲更有趣,Lostmonkey可以修改某個彈力裝置的彈力系數,任何時候彈力系數均為正整數。

輸入輸出格式

輸入格式:

第一行包含一個整數\(n\)

,表示地上有n個裝置,裝置的編號從\(0\)\(n-1\)
接下來一行有\(n\)個正整數,依次為那\(n\)個裝置的初始彈力系數。
第三行有一個正整數\(m\)
接下來\(m\)行每行至少有兩個數\(i、j\),若\(i=1\),你要輸出從j出發被彈幾次後被彈飛,若\(i=2\)則還會再輸入一個正整數\(k\),表示第\(j\)個彈力裝置的系數被修改成\(k\)

輸出格式:

對於每個\(i=1\)的情況,你都要輸出一個需要的步數,占一行。

思路

動態樹
在初始狀態下,建立動態樹,將每一個節點和通過他會彈到的節點連起來,所有會彈飛的節點都連向一個\(n+1\)號點。
對於每一個修改操作,將修改的節點和他原來會彈到的節點之間斷開,然後將它連向新的會彈到的節點。
對於每一個查詢操作,將查詢的節點和\(n+1\)

號點變成實鏈,然後把第\(n+1\)號點splay到樹頂,這是\(n+1\)號點的左子樹的大小就是需要彈的次數。

CODE

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 200010
int ch[MAXN][2],fa[MAXN],cur[MAXN],sz[MAXN];
int q[MAXN];
bool rev[MAXN];
int i,j,k,m,n,x,y,qtop;
char readc;
void read(int &n){
    while((readc=getchar())<48||readc>57);
    n=readc-48;
    while((readc=getchar())>=48&&readc<=57) n=n*10+readc-48;
}
int get(int x){
    return ch[fa[x]][1]==x;
}
bool isroot(int x){
    return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
void pushup(int x){
    sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
}
void pushdown(int x){
    if(rev[x]){
        swap(ch[x][0],ch[x][1]);
        rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
        rev[x]=false;
    }
}
void rotate(int x){
    int y=fa[x],z=fa[y],k=get(x),w=ch[x][k^1];
    ch[y][k]=w,fa[w]=y;
    if(!isroot(y)) ch[z][get(y)]=x;
    fa[x]=z;
    ch[x][k^1]=y,fa[y]=x;
    pushup(y),pushup(x);
}
void splay(int x){
    qtop=1;
    q[qtop]=x;
    for(int i=x;!isroot(i);i=fa[i]) q[++qtop]=fa[i];
    for(int i=qtop;i>=1;i--) pushdown(q[i]);
    while(!isroot(x)){
        int y=fa[x];
        if(!isroot(y)){
            if(get(x)==get(y)) rotate(y); else rotate(x);
        }
        rotate(x);
    }
    pushup(x);
}
void access(int x){
    for(int y=0;x;y=x,x=fa[x]){
        splay(x),ch[x][1]=y;
        pushup(x);
    }
}
void makeroot(int x){
    access(x);
    splay(x);
    rev[x]^=1;
}
int findroot(int x){
    access(x);
    splay(x);
    while(ch[x][0]) pushdown(x),x=ch[x][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) fa[x]=y;
    pushup(y);
}
void cut(int x,int y){
    makeroot(x);
    access(y);
    if(findroot(y)==x&&fa[x]==y&&ch[x][1]==0){
        fa[x]=0,ch[y][0]=0;
        pushup(y);
    }
}
int query(int x){
    split(x,n+1);
    return sz[ch[n+1][0]];
}
void update(int x,int y){
    int z=min(n+1,x+y);
    cut(x,cur[x]);
    link(x,z);
    cur[x]=z;
}
int main(){
    read(n);
    for(i=1;i<=n;i++) read(cur[i]),sz[i]=1;
    sz[n+1]=1;
    for(i=1;i<=n;i++){
        k=min(n+1,i+cur[i]);
        cur[i]=k;
        link(i,k);
    }
    read(m);
    for(i=1;i<=m;i++){
        read(x); read(y);
        if(x==1){
            printf("%d\n",query(y+1));
        }else{
            read(k);
            update(y+1,k);
        }
    }
    return 0;
}

洛谷P3203 [HNOI2010]彈飛綿羊