zoukankan      html  css  js  c++  java
  • 2002. [HNOI2010]弹飞绵羊【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

    把每个点像弹到的点连边,显然可得出一棵树。
    而x能弹几下显然就是x到树中在序列中最靠右的点的路径的size
    可是如果维护森林的话,很难知道这个splay中最大的是哪一个
    为了方便把弹飞的都连接到n+1点上,那么x弹的次数就是x到n+1的路径的size-1
    查询和修改操作详见代码

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define N (200000+100)
     5 using namespace std;
     6 int Father[N],Son[N][2],Size[N],Rev[N];
     7 int n,m,a[N];
     8 
     9 int Get(int x) {return Son[Father[x]][1]==x;}
    10 int Is_root(int x) {return Son[Father[x]][1]!=x && Son[Father[x]][0]!=x;}
    11 void Update(int x) {Size[x]=Size[Son[x][0]]+Size[Son[x][1]]+1;}
    12 
    13 void Rotate(int x) 
    14 {
    15     int wh=Get(x);
    16     int fa=Father[x],fafa=Father[fa];
    17     if (!Is_root(fa)) Son[fafa][Son[fafa][1]==fa]=x;
    18     Father[fa]=x; Son[fa][wh]=Son[x][wh^1];
    19     Father[x]=fafa; Son[x][wh^1]=fa;
    20     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
    21     Update(fa);    Update(x);
    22 }
    23 
    24 void Pushdown(int x)
    25 {
    26     if (Rev[x] && x)
    27     {
    28         if (Son[x][0]) Rev[Son[x][0]]^=1;
    29         if (Son[x][1]) Rev[Son[x][1]]^=1;
    30         swap(Son[x][0],Son[x][1]);
    31         Rev[x]=0;
    32     }
    33 }
    34 
    35 void Push(int x)
    36 {
    37     if (!Is_root(x)) Push(Father[x]);
    38     Pushdown(x);
    39 }
    40 
    41 void Splay(int x)
    42 {
    43     Push(x);
    44     for (int fa;!Is_root(x);Rotate(x))
    45         if (!Is_root(fa=Father[x]))
    46             Rotate(Get(fa)==Get(x)?fa:x);
    47 }
    48 
    49 void Access(int x) {for (int y=0;x;y=x,x=Father[x]) Splay(x),Son[x][1]=y,Update(x);}
    50 void Make_root(int x) {Access(x); Splay(x); Rev[x]^=1;}
    51 int Find_root(int x) {Access(x); Splay(x); while (Son[x][0]) x=Son[x][0]; return x;}
    52 void Link(int x,int y) {Make_root(x); Father[x]=y;}
    53 void Cut(int x,int y) {Make_root(x); Access(y); Splay(y); Father[x]=Son[y][0]=0;}
    54 void Query(int x) {Make_root(n+1); Access(x); Splay(x); printf("%d
    ",Size[x]-1);}
    55 void Change(int x,int y) {Cut(x,x+a[x]<=n?x+a[x]:n+1); Link(x,x+y<=n?x+y:n+1); a[x]=y;}
    56 
    57 int main()
    58 {
    59     int opt,x,y;
    60     scanf("%d",&n);
    61     for (int i=1;i<=n;++i)
    62     {
    63         scanf("%d",&a[i]);
    64         if (i+a[i]<=n) Link(i,i+a[i]);
    65         else Link(i,n+1);
    66     }
    67     scanf("%d",&m);
    68     for (int i=1;i<=m;++i)
    69     {
    70         scanf("%d",&opt);
    71         if (opt==1)    scanf("%d",&x),Query(x+1);
    72         if (opt==2)    scanf("%d%d",&x,&y),Change(x+1,y);
    73     }
    74 }
  • 相关阅读:
    HTML5响应式导航
    草原图片大全
    草原psd素材
    仿堆糖图片自滚动瀑布流效果
    夏日户外风景PSD素材
    国画经典之梅花PSD素材
    更改VS的运行主窗体
    在VS中如何更换项目名称
    如何使用Visual Studio 2008(VS2008)编译C语言
    #region 私有字段
  • 原文地址:https://www.cnblogs.com/refun/p/8680738.html
Copyright © 2011-2022 走看看