• BZOJ2002 Hnoi2010 Bounce 弹飞绵羊 【LCT】【分块】


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

    Sample Input

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

    Sample Output

    2
    3


    分块做法和LCT做法都有

    先讲讲LCT,就是一个板子,把当前点和可以连到的点连边,然后修改弹力值就是把边断开然后重新连一条边,维护的答案是一条链的长度,在这里可以直接用LCT的性质直接维护siz

    #include<bits/stdc++.h>
    using namespace std;
    #define N 200010
    #define INF 1e9
    inline int read(){
        int res=0,w=1;char c=getchar();
        while(!isdigit(c)&&c!='-')c=getchar();
        if(c=='-')w=-1,c=getchar();
        while(isdigit(c))res=(res<<1)+(res<<3)+c-'0',c=getchar();
        return res;
    }
    struct Link_Cut_Tree{
        int fa[N],son[N][2],siz[N];bool rev[N];
        Link_Cut_Tree(){memset(rev,0,sizeof(rev));}
        bool isroot(int t){return son[fa[t]][0]!=t&&son[fa[t]][1]!=t;}
        bool Son(int t){return son[fa[t]][1]==t;}
        void pushup(int t){siz[t]=siz[son[t][0]]+siz[son[t][1]]+1;}
        void pushdown(int t){
            if(!isroot(t))pushdown(fa[t]);
            if(rev[t]){
                rev[t]^=1;
                rev[son[t][0]]^=1;
                rev[son[t][1]]^=1;
                swap(son[t][0],son[t][1]);
            }
        }
        void rotate(int t){
            int f=fa[t],g=fa[f];
            bool a=Son(t),b=a^1;
            if(!isroot(f))son[g][Son(f)]=t;fa[t]=g;
            son[f][a]=son[t][b];fa[son[t][b]]=f;
            son[t][b]=f;fa[f]=t;
            pushup(f);pushup(t);
        }
        void splay(int t){
            pushdown(t);
            while(!isroot(t)){
                int f=fa[t];
                if(!isroot(f)){
                    if(Son(t)^Son(f))rotate(t);
                    else rotate(f);
                }
                rotate(t);
            }
        }
        void access(int t){
            int tmp=0;
            while(t){
                splay(t);
                son[t][1]=tmp;
                if(tmp)fa[tmp]=t;pushup(t);
                tmp=t;t=fa[t];
            }
        }
        void putroot(int t){
            access(t);
            splay(t);
            rev[t]^=1;
        }
        void link(int x,int y){putroot(x);fa[x]=y;}
        void cut(int x,int y){
            putroot(x);
            access(y);
            splay(y);
            son[y][0]=fa[x]=0;
            pushup(y);
        }
        int query(int x,int y){
            putroot(y);
            access(x);
            splay(x);
            return siz[x]-1;
        }
    }lct;
    int n,m,a[N];
    int main(){
        n=read();
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=1;i<=n;i++)
            lct.link(i,(i+a[i]>n)?n+1:i+a[i]);
        m=read();
        for(int i=1;i<=m;i++){
            int op,x,y;
            scanf("%d",&op);
            if(op==1){
                scanf("%d",&x);x++;
                printf("%d
    ",lct.query(x,n+1));
            }else{
                scanf("%d%d",&x,&y);x++;
                lct.cut(x,(x+a[x]>n)?n+1:x+a[x]);
                a[x]=y;
                lct.link(x,(x+a[x]>n)?n+1:x+a[x]);
            }
        }
        return 0;
    }

    然后讲讲分块,每次暴力跳,维护一下每个点跳出当前块的操作次数,暴力修改暴力查询就好了

    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0x7fffffff
    #define LL long long
    #define N 1000010
    const int siz=1000;
    struct Temp{int to,tmp,bel;}a[N];
    int n,m,pre[N];
    int read(){
        int ans=0,w=1;char c=getchar();
        while(!isdigit(c)&&c!='-')c=getchar();
        if(c=='-')c=getchar(),w=-1;
        while(isdigit(c))ans=ans*10+c-'0',c=getchar();
        return ans*w;
    }
    void modify(int x){
        if(a[x+pre[x]].bel!=a[x].bel){
            a[x].to=x+pre[x];
            a[x].tmp=1;
        }else{
            a[x].to=a[x+pre[x]].to;
            a[x].tmp=a[x+pre[x]].tmp+1;
        }
        return;
    }
    void build(){
        for(int i=1;i<=n;i++)a[i].bel=(i-1)/siz+1;
        for(int i=n;i>=1;i--)
            if(i+pre[i]>n)a[i].tmp=1,a[i].to=0;
            else modify(i);
    }
    int query(int x){
        int ans=0;
        while(x){
            ans+=a[x].tmp;
            x=a[x].to;
        }
        return ans;
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++)pre[i]=read();
        build();
        m=read();
        for(int i=1;i<=m;i++){
            int op=read(),x;
            if(op==1){
                x=read()+1;
                printf("%d
    ",query(x));
            }else{
                x=read()+1,pre[x]=read();
                int fro=(a[x].bel-1)*siz+1;
                for(int i=x;i>=fro;i--)modify(i);
            }
        }
        return 0;
    }
  • 相关阅读:
    redis数据类型
    golang的select实现原理剖析
    goroutine的设计与实现
    go语言的duck typing
    go语言的局部变量在堆上还是栈上?
    REDIS学习
    C++11右值引用
    C++自问
    go语言interface学习
    go语言学习(基本数据类型)
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676320.html
Copyright © 2020-2023  润新知