zoukankan      html  css  js  c++  java
  • 洛谷 P3203 [HNOI2010]弹飞绵羊(分块)

    传送门

    深夜题解

    这道题的正解应该是用动态树,但像我这种菜鸡肯定没有学过啊

    考虑用分块来莽一下,因为这道题分块的复杂度为 O(m√n) 是完全可以接受的

    首先分块常规操作,将整个数列等分为 √n 块,记录每块的左右区间,和每个位置属于哪一块。

    然后对于每一个位置 i,求出 to[i]:i 位置通过不断跳跃,跳出本块之后的位置。step[i]:i 位置跳出本块需要的最小次数。

    然后对于每一次查询 x,通过不断的迭代 x=to[x],累加 step[x],就可以在 O(√n) 的时间复杂度内求出答案。

    对于每一次修改 x 位置,我们可以暴力的调整 x 所在的整块的所有位置 to 和 step,这里的时间复杂度也是 O(√n),而其他的位置因为我们在计算 to 和 step 时的考虑范围只在该位置所处的块内,所有不受修改的影响。

    =====================分界线=====================

    仔细想一下,如果不修改,那么 O(1) 的查询方法应该谁都能写得出来,但如果在这个方法的基础上添加修改操作,那么这个修改的时间复杂度就是 O(n) 的了,放到整个题,时间复杂度就变成 O(mn) 了。

    这里用上了分块,虽然查询的时间复杂度变成了 O(√n),但同样修改的时间复杂度也降低到了 O(√n),那么解决问题的总复杂度就是降低到了 O(m√n) 了,相当于我们通过分块,均摊了查询和修改的复杂度,这就是分块思想的核心目的所在吧。

    +++++++++++++++++++康康代码++++++++++++++++++++++

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>
    #include <string.h>
    #define MAXN 200010
    using namespace std;
    int n,m,t;
    int a[MAXN],L[MAXN],R[MAXN],pos[MAXN],step[MAXN],to[MAXN];
    
    int read(){
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int main(){
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        t=sqrt(n);
        for(int i=1;i<=t;i++) L[i]=(i-1)*t+1,R[i]=i*t;
        if(R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;
        for(int i=1;i<=t;i++) for(int j=L[i];j<=R[i];j++) pos[j]=i;
        for(int i=n;i>=1;i--){
            to[i]=i+a[i];step[i]=1;
            if(to[i]<=R[pos[i]]) step[i]+=step[to[i]],to[i]=to[to[i]];
        }
        m=read();
        int opt,x,y;
        while(m--){
            opt=read();x=read();x++;
            if(opt==1){
                int ans=0,now=x;
                while(now<=n) ans+=step[now],now=to[now];
                printf("%d
    ",ans);
            }
            else if(opt==2){
                y=read();a[x]=y;
                for(int i=x;i>=L[pos[x]];i--){
                    to[i]=i+a[i];step[i]=1;
                    if(to[i]<R[pos[i]]) step[i]+=step[to[i]],to[i]=to[to[i]];
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    MySql创建库 Challenge
    未能启用约束。一行或多行中包含违反非空、唯一或外键约束的值的解决办法.
    小总结:用反射机制创建的分配数据分配器
    工厂模式的反思
    单机安装“完整”SharePoint 2010
    作业调度框架 Quartz.NET 2.0 StepByStep(2)
    UI线程同步
    每日见闻(一)
    作业调度框架 Quartz.NET 2.0 StepByStep
    基础算法(ACwing)
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/11717500.html
Copyright © 2011-2022 走看看