zoukankan      html  css  js  c++  java
  • BZOJ_2002_[Hnoi2010]Bounce 弹飞绵羊_LCT

    BZOJ_2002_[Hnoi2010]Bounce 弹飞绵羊_LCT

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

    Sample Input

    4
    1 2 1 1
    3
    1 1
    2 1 1
    1 1

    Sample Output

    2
    3


    每个位置i向i+ki的位置连一条有向边,如果出去了就向n+1连。

    形成了一棵树,每次询问相当于求一个点的深度。

    这里直接当成无根树来做,每次询问要把n+1变成根。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 200050
    #define ls ch[p][0]
    #define rs ch[p][1]
    #define get(x) (ch[f[x]][1]==x)
    int a[N],n,f[N],ch[N][2],rev[N],siz[N];
    bool isrt(int x) {return ch[f[x]][1]!=x&&ch[f[x]][0]!=x;}
    void pushup(int p) {
    	if(!p) return ;
    	siz[p]=1;
    	if(ls) siz[p]+=siz[ls];
    	if(rs) siz[p]+=siz[rs];
    }
    void pushdown(int p) {
    	if(rev[p]) {
    		rev[ls]^=1; swap(ch[ls][0],ch[ls][1]);
    		rev[rs]^=1; swap(ch[rs][0],ch[rs][1]);
    		rev[p]=0;
    	}
    }
    void update(int p) {
    	if(!isrt(p)) update(f[p]);
    	pushdown(p);
    }
    void rotate(int x) {
    	int y=f[x],z=f[y],k=get(x);
    	if(!isrt(y)) ch[z][ch[z][1]==y]=x;
    	ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
    	ch[x][!k]=y; f[y]=x; f[x]=z;
    	pushup(y); pushup(x);
    }
    void splay(int x) {
    	update(x);
    	for(int d;d=f[x],!isrt(x);rotate(x))
    		if(!isrt(d)) 
    			rotate(get(x)==get(d)?d:x);
    }
    void access(int p) {
    	for(int t=0;p;t=p,p=f[p])
    		splay(p),rs=t,pushup(p);
    }
    void makeroot(int p) {
    	access(p); splay(p); rev[p]^=1; swap(ls,rs);
    }
    void link(int x,int p) {
    	makeroot(x); splay(p); f[x]=p;
    }
    void cut(int x,int p) {
    	makeroot(x); access(p); splay(p); ls=f[x]=0;
    }
    int main() {
    	scanf("%d",&n);
    	int i;
    	for(i=1;i<=n+1;i++) siz[i]=1;
    	for(i=1;i<=n;i++) {
    		scanf("%d",&a[i]);
    		link(i,min(n+1,i+a[i]));
    	}
    	int m,opt,x,y;
    	scanf("%d",&m);
    	while(m--) {
    		scanf("%d%d",&opt,&x); x++;
    		if(opt==1) {
    			makeroot(n+1); access(x); splay(x); printf("%d
    ",siz[ch[x][0]]);
    		}else {
    			scanf("%d",&y);
    			cut(x,min(n+1,x+a[x])); a[x]=y; link(x,min(n+1,x+a[x]));
    		}
    	}
    }
    
  • 相关阅读:
    Pro Andorid3第二章:设置开发环境
    Seminar 记录
    安装CGAL
    Literature review
    第七章:清楚简洁的英文 《英语科技写作(文法与修辞原则)》by 方克涛
    幻灯片制作去除模板背景
    vs2008下设置.h, .lib和 .dll 的路径配置全图及其意义
    配置环境变量
    PPT制作技巧
    #include文件时用双引号和尖括号的区别
  • 原文地址:https://www.cnblogs.com/suika/p/9279850.html
Copyright © 2011-2022 走看看