BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊


Solution

很早以前写的一道分块题,最近在搞LCT,又做了一遍.

1.LCT做法

看到这种动态修改,想下LCT怎么维护.

修改操作就是\(Cut(x,k[x])\)然后再\(Link(x,k[x]')\)

剩下的只有询问了.

我们如果把弹出设为一个新节点\(n+1\),那么显然就是直接:

\(makeroot(x)\),\(access(n+1)\),\(splay(n+1)\).

最后答案就是\(siz[n+1].\)

2.分块做法

我们如果把编号分块,那么显然每一次修改就维护一下弹出的到了哪个块,然后随便搞一下就可以了.

代码实现

LCT

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi()
{
    int f=1,sum=0;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
const int N=300010;
int K[N],n;
struct node
{
    int ff,ch[2],siz,rev;
}t[N];
int sta[N],top;
void pushup(int x)
{
    t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+1;
}
void reverse(int x)
{
    swap(t[x].ch[0],t[x].ch[1]);
    t[x].rev^=1;
}
void pushdown(int x)
{
    if(!t[x].rev)return;
    if(t[x].ch[0])reverse(t[x].ch[0]);
    if(t[x].ch[1])reverse(t[x].ch[1]);
    t[x].rev^=1;
}
bool isroot(int x)
{
    return (t[t[x].ff].ch[0]!=x) && (t[t[x].ff].ch[1]!=x);
}
void rotate(int x)
{
    int y=t[x].ff,z=t[y].ff;
    int k=t[y].ch[1]==x;
    if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;//只能在这一棵Splay里面Rotate
    t[x].ff=z;
    t[y].ch[k]=t[x].ch[k^1];
    t[t[x].ch[k^1]].ff=y;
    t[x].ch[k^1]=y;t[y].ff=x;
    pushup(y);pushup(x);
}
void splay(int x)
{
    sta[++top]=x;
    for(int i=x;!isroot(i);i=t[i].ff)sta[++top]=t[i].ff;
    while(top)pushdown(sta[top--]);
    while(!isroot(x))
    {
        int y=t[x].ff,z=t[y].ff;
        if(!isroot(y))//Splay是旋转到当前这棵Splay的根,这个道理就和上面的rotate是一样的.
            (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
        rotate(x);
    }
    pushup(x);
}
void access(int x)
{
    for(int y=0;x;y=x,x=t[x].ff)
    {
        splay(x);
        t[x].ch[1]=y;
        pushup(x);
    }
}
void makeroot(int x)
{
    access(x);splay(x);
    reverse(x);
}
int findroot(int x)
{
    access(x);splay(x);
    while(t[x].ch[0])x=t[x].ch[0];
    return x;
}
void split(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
}
void link(int x,int y)
{
    makeroot(x);
    t[x].ff=y;
}
void cut(int x,int y)
{
    split(x,y);
    t[y].ch[0]=t[x].ff=0;
}
int judge(int x)
{
    return x>n?n+1:x;
}
int main()
{
    n=gi();
    for(int i=1;i<=n;i++)
        t[i].siz=1;
    for(int i=1;i<=n;i++)
        link(i,judge(i+(K[i]=gi())));
    int Q=gi();
    while(Q--)
    {
        int opt=gi(),u=gi();u++;
        if(opt==1)
        {
            makeroot(u);access(n+1);splay(n+1);
            printf("%d\n",t[n+1].siz-1);
        }
        if(opt==2)
        {
            int tmp=K[u];
            K[u]=gi();
            cut(u,judge(u+tmp));
            link(u,judge(u+K[u]));
        }
    }
    return 0;
}

分块

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
inline int gi(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
const int N=400010;
int bl[N],nxt[N],sum[N],a[N];
int n,B,m;
void ask(int l,int r){
    for(int i=r;i>=l;i--)
        if(i+a[i]>min(n,bl[i]*B))sum[i]=1,nxt[i]=i+a[i];
        else sum[i]=sum[i+a[i]]+1,nxt[i]=nxt[i+a[i]];
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    n=gi();B=sqrt(n);
    for(int i=1;i<=n;i++)a[i]=gi();
    for(int i=1;i<=n;i++)
        bl[i]=(i-1)/B+1;
    ask(1,n);
    m=gi();int all=bl[n];
    while(m--){
        int opt=gi(),x=gi();x++;
        if(opt==1){
            int ans=sum[x],now=nxt[x],i=bl[x];
            while(now<=n && i<=all){ans+=sum[now];now=nxt[now];i++;}
            printf("%d\n",ans);
        }
        else{
            int k=gi();
            a[x]=k;
            ask((bl[x]-1)*B+1,min(bl[x]*B,n));
        }
    }
    return 0;
}

【BZOJ2002】 [Hnoi2010]Bounce 弹飞绵羊的更多相关文章

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

    BZOJ2002 Hnoi2010 Bounce 弹飞绵羊 Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始, ...

  2. [bzoj2002][Hnoi2010]Bounce弹飞绵羊_LCT

    Bounce弹飞绵羊 bzoj-2002 Hnoi-2010 题目大意:n个格子,每一个格子有一个弹簧,第i个格子会将经过的绵羊往后弹k[i]个,达到i+k[i].如果i+k[i]不存在,就表示这只绵 ...

  3. bzoj2002: [Hnoi2010]Bounce 弹飞绵羊 [分块][LCT]

    Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置 ...

  4. [BZOJ2002] [Hnoi2010] Bounce 弹飞绵羊 (LCT)

    Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置 ...

  5. [bzoj2002][Hnoi2010]Bounce弹飞绵羊——分块

    Brief description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装 ...

  6. BZOJ2002: [Hnoi2010]Bounce 弹飞绵羊(LCT)

    Description 某天,Lostmonkey发明了一种超级弹力装置,为了在 他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装 ...

  7. bzoj2002 [Hnoi2010]Bounce 弹飞绵羊——分块

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2002 第一次用分块,感觉超方便啊: 如果记录每个点的弹力系数,那么是O(1)修改O(n)查询 ...

  8. bzoj2002 [Hnoi2010]Bounce 弹飞绵羊【分块】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2002 这一题除了LCT解法,还有一种更巧妙,代码量更少的解法,就是分块.先想,如果仅仅记录每 ...

  9. 题解【bzoj2002 [Hnoi2010]Bounce 弹飞绵羊】

    Description 给 \(n\) 个点以及它们的弹力系数 \(k_i\) ,含义为 可以弹到 \(i + k_i\) 的位置. 支持两个东西,修改一个点的弹力系数:求一个点要弹多少次弹出 \(n ...

  10. 【lct】bzoj2002 [Hnoi2010]Bounce 弹飞绵羊

    lct板子,此题主要有cut操作和link操作. #include<cstdio> #include<iostream> #include<cstring> #in ...

随机推荐

  1. .net利用NPOI生成excel文件

    整理代码,这个是生成excel文件,用的是HSSF的方式,只能生成65535行,256列的数据,如果要看office07之后的生成,之前的随笔里提过.这个是一个完整的过程. 首先是已经查找好的数据,这 ...

  2. 【Go】 Go 语言环境安装

    安装环境/工具 1.Linux(CentOS 7.4版) 2.go1.11.2.linux-amd64.tar Go 语言环境安装 1.下载安装包 安装包下载地址为:https://golang.or ...

  3. 20155312 2006-2007-2 《Java程序设计》第三周学习总结

    20155312 2006-2007-2 <Java程序设计>第三周学习总结 课堂内容总结 yyp复制上一行代码 5不是false statistics.sh换成.bat就可以在windo ...

  4. keras框架的MLP手写数字识别MNIST,梳理?

    keras框架的MLP手写数字识别MNIST 代码: # coding: utf-8 # In[1]: import numpy as np import pandas as pd from kera ...

  5. ant Design和ant Design mobile的使用,并实现按需加载

    1.全局安装yarn npm install -g create-react-app yarn 2.创建react项目,并用yarn start 运行 3.引入antd/引入antd-mobile y ...

  6. Tomcat服务器的安装和配置

    一.Tomcat下载 可以直接从Apache的网站上下载Tomcat(http://tomcat.apache.org/),进入首页后,在左边Download一栏可选择你要下载的版本,点击便可进入To ...

  7. Mybatis-Plus 实战完整学习笔记(五)------insert测试

    一.更新操作探究(3.0.3版本) demo /** * 修改用户 * @throws SQLException */ @Test public void update() throws SQLExc ...

  8. IntelliJ IDEA 2017版 spring-boot 拦截器的操作三种方式

    一.注解方式 @WebServlet(urlPatterns = "/myServlet") public class MyServlet extends HttpServlet ...

  9. INtellJ IDEA 2017 创建Annotation注解类

    1.建立一个文件夹 java ------->new ---->Package--->输入名字 2.New ---->java class --->如图修改红圈位置的下拉 ...

  10. UVa 11542 Square (高斯消元)

    题意:给定 n 个数,从中选出一个,或者是多个,使得选出的整数的乘积是完全平方数,求一共有多少种选法,整数的素因子不大于 500. 析:从题目素因子不超过 500,就知道要把每个数进行分解.因为结果要 ...