[BZOJ 2002][Luogu 3203][HNOI2010]Bounce 弹飞绵羊

Posted trisolaris

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 2002][Luogu 3203][HNOI2010]Bounce 弹飞绵羊相关的知识,希望对你有一定的参考价值。

[BZOJ 2002][Luogu 3203][HNOI2010]Bounce 弹飞绵羊

 

<题意概括>

给定一个数列$\left\{k_{N}\right\}$,数列长度为n,k次操作

要求支持两种操作

1.求最少对数x进行几次变换才能满足条件$x>n$(一次操作定义为$x=x+k_{x}$)

2.$k_{x}$修改为a

 

<做法>

通过建模我们可以将题目转化为如下的问题

建一个图,将图中每个顶点i和顶点$i+k_{i}$连边

那么操作一就转化为了求顶点i到任一编号大于n的顶点的最短路长度

但是这样可能有很多编号大于n的顶点,不方便统计

于是我们将编号大于n的顶点缩为一个编号为$n+1$的点

这样操作一就相当于求顶点i到顶点$n+1$的最短路长度

操作二则是断开边(i,$i+k_{i}$),$k_{i}$修改为a一条新边(i,$i+k_{i}$)

由操作二的动态断边连边可以想到使用Link-Cut Tree去维护这个图

则操作一就是MakeRoot(x),Access(n+1),Splay(n+1),此时$Answer=Size_{n+1}-1$

因为在MakeRoot(x)Access(n+1),Splay(n+1)后,$x\leftrightarrow n+1$全在以rootn+1Auxiliary Tree

Answer就是该Auxiliary TreerootSize-1(去点n+1)

操作二就是Cut(x,x+K[x]>N?N+1:x+K[x]);K[x]=y;Link(x,x+K[x]>N?N+1:x+K[x]);

  

<Code> 

技术分享图片
#include<cstdio>
#include<algorithm>
using namespace std;
#define Fast register
inline char Getchar(){
    static char BUF[16384],*S=BUF,*T=BUF;
    return(S==T)&&(T=(S=BUF)+fread(BUF,1,16384,stdin),S==T)?EOF:*S++;
}
inline int Getint(){
    Fast int s=0;Fast char c=Getchar();
    while(c<48||c>57)c=Getchar();
    while(c>47&&c<58)s=s*10+c-48,c=Getchar();
    return s;
}
struct Node{
    int lson,rson,p,size;
    bool rev;
    Node():lson(0),rson(0),p(0),size(0),rev(false){}
    Node(int key):lson(0),rson(0),p(0),size(0),rev(false){}
}node[200002];
#define ls(o) node[o].lson
#define rs(o) node[o].rson
#define Fa(o) node[o].p
#define Size(o) node[o].size
#define Rev(o) node[o].rev

inline void update(const int&o){if(o)Size(o)=Size(ls(o))+Size(rs(o))+1;}

inline void push_down(const int&o){
    if(!Rev(o))return;
    swap(ls(o),rs(o));
    Rev(ls(o))^=1;
    Rev(rs(o))^=1;
    Rev(o)=false;
}

inline bool IsRoot(const int&o){return ls(Fa(o))!=o&&rs(Fa(o))!=o;}

inline void rotate(const int&o){
    Fast int p=Fa(o),gp=Fa(p);
    if(!IsRoot(p)){
        if(ls(gp)==p)ls(gp)=o;
        else rs(gp)=o;
    }
    Fa(o)=gp;
    Fa(p)=o;
    if(ls(p)==o)Fa(rs(o))=p,ls(p)=rs(o),rs(o)=p;
    else Fa(ls(o))=p,rs(p)=ls(o),ls(o)=p;
    update(p);
    update(o);
}

inline void Splay(const int&o){
    int Stack[200001];
    Fast int Top=0;
    Stack[++Top]=o;
    for(Fast int i=o;!IsRoot(i);i=Fa(i))Stack[++Top]=Fa(i);
    while(Top)push_down(Stack[Top--]);
    while(!IsRoot(o)){
        if(!IsRoot(Fa(o))){
            if(ls(Fa(o))==o^ls(Fa(Fa(o)))==Fa(o))rotate(o);
            else rotate(Fa(o));
        }
        rotate(o);
    }
}

inline void Access(int o){
    for(Fast int k=0;o;k=o,o=Fa(o)){
        Splay(o);
        rs(o)=k;
        update(o);
    }
}

inline void MakeRoot(const int&o){
    Access(o);
    Splay(o);
    Rev(o)^=1;
}

inline int Find(int o){
    Access(o);
    Splay(o);
    while(ls(o))o=ls(o);
    return o;
}

inline void Link(const int&x,const int&y){
    MakeRoot(x);
    Fa(x)=y;
}

inline void Cut(const int&x,const int&y){
    MakeRoot(x);
    Access(y);
    Splay(y);
    if(ls(y)==x)ls(y)=Fa(x)=0;
}
int K[200001];
int main(){
    Fast int N=Getint(),M,x,y,opt;
    for(Fast int i=1;i<=N;++i)K[i]=Getint(),Link(i,i+K[i]>N?N+1:i+K[i]);
    M=Getint()+1;
    while(--M){
        opt=Getint(),x=Getint()+1;
        if(opt&1){
            MakeRoot(x);
            Access(N+1);
            Splay(N+1);
            printf("%d\n",Size(N+1)-1);
        }
        else{
            y=Getint();
            Cut(x,x+K[x]>N?N+1:x+K[x]);
            K[x]=y;
            Link(x,x+K[x]>N?N+1:x+K[x]);
        }
    }
    return 0;
}
[BZOJ 2002][Luogu 3203][HNOI2010]Bounce 弹飞绵羊 




以上是关于[BZOJ 2002][Luogu 3203][HNOI2010]Bounce 弹飞绵羊的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P3203 [HNOI2010]弹飞绵羊 || bzoj2002

BZOJ2002:[HNOI2010]弹飞绵羊——题解

BZLJ 3203 Luogu P3299 [SDOI2013]保护出题人 (凸包斜率优化二分)

BZOJ3203[Sdoi2013]保护出题人 二分+凸包

[bzoj3203][Sdoi2013]保护出题人

bzoj3203: [Sdoi2013]保护出题人