• BZOJ3343: 教主的魔法 分块


    2016-05-28  10:27:19

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3343

    比较显然的分块题,分块后块内排序,维护整块的附加信息add

    对于操作来说,l,r所在的块暴力,其它块内直接加add,或二分查找大于某个值的数有多少个。

    神奇WA

    update:本傻叉的二分写法太过傻叉,卒于tmp没有赋初值

     1 #include<bits/stdc++.h>
     2 #define inf 1000000000
     3 #define N 1000005
     4 #define ll long long
     5 using namespace std;
     6 int read(){
     7   int x=0,f=1;char ch=getchar();
     8   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     9   while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    10   return x*f;
    11 }
    12 int n,q,m,block,a[N],b[N],pos[N],add[N];
    13 void reset(int x){
    14   int l=(x-1)*block+1,r=min(x*block,n);
    15   for(int i=l;i<=r;i++)b[i]=a[i];
    16   sort(b+l,b+r+1);
    17 }
    18 void update(int x,int y,int v){
    19   if(pos[x]==pos[y]){
    20     for(int i=x;i<=y;i++)a[i]+=v;
    21   }
    22   else{
    23     for(int i=x;i<=pos[x]*block;i++)a[i]+=v;
    24     for(int i=(pos[y]-1)*block+1;i<=y;i++)a[i]+=v;
    25   }
    26   reset(pos[x]);reset(pos[y]);
    27   for(int i=pos[x]+1;i<pos[y];i++)add[i]+=v;
    28 }
    29 int find(int x,int v){
    30   int l=(x-1)*block+1,r=min(x*block,n),last=r,mid,tmp=r+1;
    31   while(l<=r){
    32     mid=l+r>>1;
    33     if(b[mid]>=v)tmp=mid,r=mid-1;
    34     else l=mid+1;
    35   }
    36   return last-tmp+1;
    37 }
    38 int query(int x,int y,int v){
    39   int sum=0;
    40   if(pos[x]==pos[y]){
    41     for(int i=x;i<=y;i++)if(a[i]+add[pos[x]]>=v)sum++;
    42   }
    43   else{
    44     for(int i=x;i<=pos[x]*block;i++)
    45       if(a[i]+add[pos[x]]>=v)sum++;
    46     for(int i=(pos[y]-1)*block+1;i<=y;i++)
    47       if(a[i]+add[pos[y]]>=v)sum++;
    48   }
    49   for(int i=pos[x]+1;i<pos[y];i++)
    50     sum+=find(i,v-add[i]);
    51   return sum;
    52 }
    53 int main(){
    54   n=read();q=read();
    55   block=(int)sqrt(n);
    56   for(int i=1;i<=n;i++){
    57     a[i]=read();
    58     pos[i]=(i-1)/block+1;
    59     b[i]=a[i];
    60   }
    61   if(n%block)m=n/block+1;
    62   else m=n/block;
    63   for(int i=1;i<=m;i++)reset(i);
    64   for(int i=1;i<=q;i++){
    65     char ch[5];
    66     scanf("%s",ch);
    67     int x=read(),y=read(),v=read();
    68     if(ch[0]=='M')update(x,y,v);
    69     else printf("%d
    ",query(x,y,v));
    70   }
    71   return 0;
    72 }
    View Code

    3343: 教主的魔法

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 984  Solved: 430
    [Submit][Status][Discuss]

    Description

    教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N
    每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[LR](1≤LRN)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第LR)个英雄的身高)
    CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [LR] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。
    WD巨懒,于是他把这个回答的任务交给了你。
     

    Input

           第1行为两个整数NQQ为问题数与教主的施法数总和。
           第2行有N个正整数,第i个数代表第i个英雄的身高。
           第3到第Q+2行每行有一个操作:
    (1)       若第一个字母为“M”,则紧接着有三个数字LRW。表示对闭区间 [LR] 内所有英雄的身高加上W
    (2)       若第一个字母为“A”,则紧接着有三个数字LRC。询问闭区间 [LR] 内有多少英雄的身高大于等于C
     

    Output

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

    Sample Input

    5 3
    1 2 3 4 5
    A 1 5 4
    M 3 5 1
    A 1 5 4

    Sample Output

    2
    3

    HINT

    【输入输出样例说明】

    原先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。
  • 相关阅读:
    Minimum configuration for openldap to proxy multiple AD into a single search base
    排列组合算法(PHP)
    Make Notepad++ auto close HTML/XML tags after the slash(the Dreamweaver way)
    PHP, LDAPS and Apache
    【day1】tensorflow版本问题及初步使用
    tflearn save模型异常
    布隆过滤器(Bloom Filter)
    初识Spark(Spark系列)
    Hadoop实践
    install postgis(2.0) on ubuntu(12.04)
  • 原文地址:https://www.cnblogs.com/wjyi/p/5536922.html
Copyright © 2020-2023  润新知