zoukankan      html  css  js  c++  java
  • 分块 && 例题 I Hate It HDU

    分块算法:

    分块就是对暴力方法的一种优化:                          _

    假设我们总共的序列长度为n,然后我们把它切成√n 块,然后把每一块里的东西当成一个整体来看,
    完整块:被操作区间完全覆盖的块
    不完整块:操作区间不完全覆盖的块

    在对区间的询问中,对于完整块我们就去找维护这个块的数组。比如我们要找[l,r]这个区间中所有数的和,那么我们再把这n个数分块之后肯定要找一个数组去记录一下每一块中所有数的和(如果按照暴力的方式肯定是从l到r遍历,而分块对暴力方法的优化就是在完整块上不需要去遍历)。

    对于不完整块的询问,那就遍历这个不完整块就可以了

    其实和线段树很相似,分块的实际代码比线段树要简单些!

    复杂度:O( nsqrt( n ) ) + O( nsqrt( m ) )   (n是序列长度,m是查询区间次数

    题目:

    很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
    这让很多学生很反感。

    不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。

    Input本题目包含多组测试,请处理到文件结束。
    在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
    学生ID编号分别从1编到N。
    第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
    接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。
    当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
    当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
    Output对于每一次询问操作,在一行里面输出最高成绩。Sample Input

    5 6
    1 2 3 4 5
    Q 1 5
    U 3 6
    Q 3 4
    Q 4 5
    U 2 9
    Q 1 5

    Sample Output

    5
    6
    5
    9
    
    
            
     

    Hint

    Huge input,the C function scanf() will work better than cin

    分析:

    题意很清晰,按照对分块的理解我们就应该找一个数组去维护一下分块后每一块的区间最大值

    具体分块看代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<math.h>
     6 using namespace std;
     7 const int maxn=200005;
     8 int n,m,a[maxn],block,num,l[maxn],r[maxn],maxx[maxn],belong[maxn];
     9 //l数组决定分块后每一块区间的左端点,r数组决定分块后每一块区间的右端点
    10 //belong数组决定这一个位置属于哪一个块
    11 //maxx数组就是维护分块后区间最大值的
    12 //num代表一共有多少块
    13 void build()
    14 {
    15     block=sqrt(n);
    16     num=n/block;
    17     for(int i=1; i<=num; ++i)
    18     {
    19         l[i]=block*(i-1)+1;
    20         r[i]=block*i;
    21     }
    22     r[num]=n;
    23 
    24     for(int i=1; i<=num; ++i)
    25     {
    26         int ans=0;
    27         for(int j=l[i]; j<=r[i]; ++j)
    28         {
    29             ans=max(ans,a[j]);
    30             belong[j]=i;
    31         }
    32         maxx[i]=ans;
    33     }
    34 }
    35 int query(int x,int y)
    36 {
    37     int ans=0;
    38     if(belong[x]==belong[y])
    39     {
    40         for(int i=x; i<=y; ++i)
    41         {
    42             ans=max(ans,a[i]);
    43         }
    44     }
    45     else
    46     {
    47         for(int i=x; i<=r[belong[x]]; i++) ans=max(ans,a[i]); //对于不完整块要遍历
    48         for(int i=belong[x]+1; i<belong[y]; i++)  //完整块直接访问维护数组maxx就完了
    49             ans=max(ans,maxx[i]);
    50         for(int i=l[belong[y]]; i<=y; i++) ans=max(ans,a[i]);  //对于不完整块要遍历
    51     }
    52     return ans;
    53 }
    54 void update(int x,int y)
    55 {
    56     maxx[belong[x]]=max(maxx[belong[x]],y);
    57     a[x]=y;  //更新的时候维护最大值数组要更新且原位置也要更新
    58 }
    59 int main()
    60 {
    61     int x,y;
    62     char ch[5];
    63     while(~scanf("%d%d",&n,&m))
    64     {
    65         for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    66         build();
    67         while(m--)
    68         {
    69             scanf("%s%d%d",ch,&x,&y);
    70             if(ch[0]=='Q')
    71             {
    72                 printf("%d
    ",query(x,y));
    73             }
    74             else
    75             {
    76                 update(x,y);
    77             }
    78         }
    79     }
    80     return 0;
    81 }
  • 相关阅读:
    输入一个1-9的数i,再输入一个数字n,表示 i 出现的次数,输入的2个数字 i 和 n 组合成如下表达式:如i=2,n=4,2+22+222+2222=?,计算结果是多少?
    现有数列1/2;2/3;3/5;5/8······第十次出现的是什么?
    猜数游戏:范围时1-100,若错误就提示大了还是小了,猜对则结束,允许猜10次,游戏结束后对玩家评价:1次猜对;5次内猜对;10次内猜对;没有猜对
    登录模拟,用户名和密码输入错误后给出相关错误提示,并告知还有多少次错误机会,如果5次验证失败将冻结账户
    30人围坐轮流表演节目,按顺序数1-3,每次数到3的人就表演节目,表演过的人不再参加报数,那么在仅剩一个人没有表演的时候,共报数多少人次?
    docker 自定义镜像
    php 镜像richarvey/nginx-php-fpm的ngnix配置
    php tp5常用小知识
    php Tp5下mysql的增删改查
    php 面试常问问题
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11970975.html
Copyright © 2011-2022 走看看