zoukankan      html  css  js  c++  java
  • [bzoj3343]教主的魔法

    题目描述

    教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。

    每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)

    CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。

    WD巨懒,于是他把这个回答的任务交给了你。

    输入输出格式

    输入格式:

    第1行为两个整数N、Q。Q为问题数与教主的施法数总和。

    第2行有N个正整数,第i个数代表第i个英雄的身高。

    第3到第Q+2行每行有一个操作:

    (1) 若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。

    (2) 若第一个字母为“A”,则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。

    输出格式:

    对每个“A”询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于C的英雄数。

    输入输出样例

    输入样例#1:
    5 3
    
    1 2 3 4 5
    
    A 1 5 4
    
    M 3 5 1
    
    A 1 5 4
    输出样例#1:
    2
    3
    

    说明

    【输入输出样例说明】

    原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。

    【数据范围】

    对30%的数据,N≤1000,Q≤1000。

    对100%的数据,N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000。

    解题思路

    分块打标记,每个块单独排序,查找时每个块内二分答案,更新区间时区间两端重建,中间直接更新标记,复杂度O(n*√n),完毕

    源代码

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cmath>
     4 #include <algorithm>
     5 #include <vector>
     6 #define LL long long
     7 using namespace std;
     8 inline int readn(){
     9     int rtn=0,f=1;char ch=getchar();
    10     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    11     while(ch<='9'&&ch>='0')rtn=rtn*10+ch-'0',ch=getchar();
    12     return rtn*f;
    13 }
    14 inline char readc(){
    15     char ch=getchar();
    16     while(ch>'Z'||ch<'A')ch=getchar();
    17     return ch;
    18 }
    19 const int N=1001000;
    20 int n,q,blo;
    21 int v[N],bl[N];
    22 int ve[N],atag[N];
    23 void reset(int x){
    24     int l=(x-1)*blo+1,r=min(n,x*blo)+1;
    25     for(int i=l;i<r;i++)
    26         ve[i]=v[i];
    27     sort(ve+l,ve+r);
    28 }
    29 int finds(int x,int val){
    30     int l=(x-1)*blo+1,r=min(x*blo,n)+1;
    31     int rtn=r-1;
    32     while(l<r){
    33         int mid=(l+r)>>1;
    34         if(ve[mid]<val)l=mid+1;
    35         else r=mid;
    36     }
    37     return rtn-l+1;
    38 }
    39 void add(int l,int r,int m){
    40     for(int i=bl[l]+1;i<bl[r];i++)atag[i]+=m;
    41     if(bl[l]==bl[r]){
    42         for(int i=l;i<=r;i++)v[i]+=m;
    43     }
    44     else{
    45         for(int i=l;i<=bl[l]*blo;i++)v[i]+=m;
    46         for(int i=(bl[r]-1)*blo+1;i<=r;i++)v[i]+=m;
    47     }
    48     reset(bl[l]);reset(bl[r]);
    49 }
    50 
    51 int query(int l,int r,int c){
    52     int ans=0;
    53     for(int i=bl[l]+1;i<bl[r];i++)ans+=finds(i,c-atag[i]);
    54     if(bl[l]==bl[r]){
    55         for(int i=l;i<=r;i++)if(v[i]+atag[bl[i]]>=c)ans++;
    56     }
    57     else {
    58         for(int i=l;i<=bl[l]*blo;i++)if(v[i]+atag[bl[i]]>=c)ans++;
    59         for(int i=(bl[r]-1)*blo+1;i<=r;i++)if(v[i]+atag[bl[i]]>=c)ans++;
    60     }
    61     return ans; 
    62 }
    63 int main(){
    64     n=readn();q=readn();blo=sqrt(n);
    65     for(int i=1;i<=n;i++){
    66         bl[i]=(i-1)/blo+1;
    67         v[i]=readn();
    68     }
    69     for(int i=1;i<=bl[n];i++)reset(i);
    70     while(q--){
    71         char opt=readc();int l=readn(),r=readn(),c=readn();
    72         if(opt=='M')add(l,r,c);
    73         else printf("%d
    ",query(l,r,c));
    74     }
    75     return 0;
    76 }
  • 相关阅读:
    201671010119 2016-2017-2《Java程序设计》第十四周学习心得
    201671010119 2016-2017-2《Java程序设计》第十三周学习心得
    201671010119 2016-2017-2《Java程序设计》第十二周学习心得
    201671010119 2016-2017-2《Java程序设计》第十一周学习心得
    201671010119 2016-2017-2《Java程序设计》第十周学习心得
    201671010119 2016-2017-2《Java程序设计》第九周学习心得
    201671010118 2016-2017-2《Java程序设计》 面向对象程序设计课程学习进度条
    201671010118 2016-2017-2《Java程序设计》 第十八周学习心得
    201671010118 2016-2017-2《Java程序设计》 第十七周学习心得
    201671010118 2016-2017-2《Java程序设计》 第十六周学习心得
  • 原文地址:https://www.cnblogs.com/Anoxiacxy/p/6898068.html
Copyright © 2011-2022 走看看