bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊

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的情况,你都要输出一个需要的步数,占一行。

关于LCT的讲解可以参见我的另一篇博文里面讲的还算比较详细。
->LCT讲解戳这里<-
本题就是一道LCT的模板题,,第i个位置的绵羊被弹飞到i+k个位置,就在i和i+k之间连边,可以知道每个点仅有一个弹力系数,就是说满足树的性质,所以用LCT即可,更改弹力系数就是将i个位置的父边断开并连到新的节点i+k上,如果i+k>n的话,就将它连到0节点(空节点),使之成为另一棵树,这样每次询问实质上就是询问某个节点的深度。在询问深度时,先access(o),使节点o与根接节点在一棵splay中,然后splay(o),这样o就成为了splay的根,由于splay中是用深度当作关键字的,而节点到根的路径中,显然o 的深度最大,所以当o变为根节点时,splay中的其他点都在o点的左子树上,且这些节点就是o到根的路径,那么这些节点的个数就是该节点的深度,根据题意,某个点在弹出时,弹飞的次数=深度+1,所以输出o点左子树的节点数+1即可;
这是我第一次写LCT,,代码被我调的乱七八糟,,所以没有当作模板,想看模板请参照我的另外一篇:

LCT模板戳这里

本题代码如下:

#include
#include
#define N 200010
#define lch(o) t[o].ch[0]
#define rch(o) t[o].ch[1]
using namespace std;
struct node { 
    int ch[2],re,fa,size; 
    node() { re=ch[0]=ch[1]=fa=0;size=1; }
}t[N];
int n,m;
bool is(int o) { if(lch(t[o].fa)==o) return 0;return 1; }
bool isroot(int o) { return (!t[o].fa)||(lch(t[o].fa)!=o&&rch(t[o].fa)!=o); }
void markdown(int now) {
    if(t[now].re) {
      if(t[now].ch[0]) t[lch(now)].re^=1;
      if(t[now].ch[1]) t[rch(now)].re^=1;
      swap(lch(now),rch(now));t[now].re=0;
    }
}
void update(int now) {
    t[now].size=1;
    if(lch(now)) t[now].size+=t[lch(now)].size;
    if(rch(now)) t[now].size+=t[rch(now)].size;
}
void rorate(int now) {
    int fa=t[now].fa,d=is(now),c=t[now].ch[d^1];
    if(c) t[c].fa=fa; t[fa].ch[d]=c;
    t[now].fa=t[fa].fa;
    if(!isroot(fa)) t[t[fa].fa].ch[is(fa)]=now;
    t[fa].fa=now; t[now].ch[d^1]=fa;
    update(fa); update(now);
}
void splay(int now) {
    if(now==0) return;
    markdown(t[now].fa);
    markdown(now);
    while(!isroot(now)) {
      markdown(t[now].fa);markdown(now);
      rorate(now);
    }
}
void access(int o,int x=0) { 
    for(;o;x=o,o=t[o].fa) 
      splay(o),rch(o)=x; 
}
void cut(int u) { 
    access(u); splay(u);
    int c=t[u].ch[0],fa=t[u].fa;
    t[c].fa=fa; t[u].ch[0]=0; t[u].fa=0;
    update(u);
}
void link_cut(int u,int v) { 
    cut(u); t[u].fa=v; return; 
}
int in(int s=0,char c=getchar()) {
    while(c<'0'||c>'9') c=getchar();s=c-'0';
    while((c=getchar())>='0'&&c<='9') 
      s=s*10+c-'0';return s;
}
int main() {
    int i=0;n=in();while(++i<=n) {
      int k=in(); if(i+k<=n) {
        t[i+k].size+=t[i].size;t[i].fa=i+k;
      }
    } t[0].size=0;
    m=in();while(m--) {
      i=in();if(i==1) {
        int j=in()+1; access(j); splay(j); 
        printf("%d\n",t[t[j].ch[0]].size+1);
      }
      else {
        int j=in()+1,k=in();
        if(j+k<=n) link_cut(j,j+k); else cut(j);
      }
    }
}

你可能感兴趣的:(树形结构,LCT,模板)