zoukankan      html  css  js  c++  java
  • [BZOJ2002][洛谷P3203][Hnoi2010]Bounce 弹飞绵羊(LCT维护链长)

    luogu传送门

    2002: [Hnoi2010]Bounce 弹飞绵羊

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 16082  Solved: 8241
    [Submit][Status][Discuss]

    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

    HINT

    Source

    Solution

      我们按1-n编号哈,不用题目中的从0开始编号,因为0这个节点在蒟蒻写的LCT里面比较暧昧(雾),用它我会很方。。。

      对于每个i如果k+k[i]<=n,那么视为存在边i->k+k[i],否则视为存在边i->虚拟节点n+1。然后你会发现每个节点有且仅有一条出边,O,你想到了什么?内向树!然而节点n+1并没有出边所以这是一棵普通的树(不然怎么用LCT呢)。

      然后对于查询x的答案就是x到n+1的链长,这个其实顺手就求出来了,只需要维护sz,然后split一下x和n+1,答案就是此时根的sz值减1。

      至于修改操作,就是cut一下再link一下嘛。

      还有就是,我再也不在BZOJ上随便用cout了,这常数也忒大了。。。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+5;
    inline int read(){
        int x=0,w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return w?-x:x;
    }
    int sz[N],f[N],c[N][2];
    bool rv[N];
    #define lc c[x][0]
    #define rc c[x][1]
    inline bool nrt(int x){return c[f[x]][0]==x||c[f[x]][1]==x;}
    inline void pushup(int x){sz[x]=sz[lc]+sz[rc]+1;}
    inline void rev(int x){lc^=rc^=lc^=rc;rv[x]^=1;}
    inline void pushdown(int x){if(rv[x]) rev(lc),rev(rc),rv[x]=0;}
    inline int get(int x){return c[f[x]][1]==x;}
    inline void link(int x,int y,int d){c[x][d]=y,f[y]=x;}
    void rotate(int x){
        int y=f[x],z=f[y],d=get(x);
        if(nrt(y)) c[z][get(y)]=x;f[x]=z;
        link(y,c[x][d^1],d);
        link(x,y,d^1);
        pushup(y),pushup(x);
    }
    int st[N],tp;
    void splay(int x){
        int t=x;
        st[tp=1]=t;
        while(nrt(t)) st[++tp]=t=f[t];
        while(tp) pushdown(st[tp--]);
        for(;nrt(x);rotate(x))
            if(nrt(f[x])) get(x)^get(f[x])?rotate(x):rotate(f[x]);
    }
    void access(int x){
        for(int y=0;x;x=f[y=x])
            splay(x),c[x][1]=y,pushup(x);
    }
    void makert(int x){access(x),splay(x),rev(x);}
    int findrt(int x){
        access(x),splay(x);
        while(lc) pushdown(x),x=lc;
        splay(x);return x;
    }
    void link(int x,int y){
        makert(x);if(findrt(y)^x) f[x]=y;
    }
    void cut(int x,int y){
        makert(x);
        if(findrt(y)==x&&f[y]==x&&!c[y][0]) f[y]=c[x][1]=0,pushup(x);
    }
    void split(int x,int y){
        makert(x),access(y),splay(y);
    }
    int n,m,k[N];
    #define to(x) min(x+k[x],n+1)
    int main(){
        n=read();
        for(int i=1;i<=n;++i) k[i]=read(),link(i,to(i));
        m=read();
        while(m--){
            int x=read(),y=read()+1;
            if(x&1){
                split(y,n+1);
                printf("%d
    ",sz[n+1]-1);
            }
            else{
                cut(y,to(y));
                k[y]=read();
                link(y,to(y));  
            }
        }
        return 0;
    }
    BZOJ2002

      

  • 相关阅读:
    抽象工厂模式
    工厂方法模式
    assert断言
    非日志警告
    requests获取所有状态码
    在线工具、资料
    重定向、feed输出:控制台输出的内容存放到文件
    正则表达式python
    python提取相对路径
    logger类
  • 原文地址:https://www.cnblogs.com/gosick/p/11256790.html
Copyright © 2011-2022 走看看