分块入门

洛谷 2068

题目描述

给定一个长度为n(n<=100000),初始值都为0的序列,x(x<=10000)次的修改某些位置上的数字,每次加上一个数,然后提出y (y<=10000)个问题,求每段区间的和。时间限制1秒。

输入输出格式

输入格式:

 

第一行1个数,表示序列的长度n

第二行1个数,表示操作的次数w

后面依次是w行,分别表示加入和询问操作

其中,加入用x表示,询问用y表示

x的格式为"x a b" 表示在序列a的位置加上b

y的格式为"y a b" 表示询问a到b区间的加和

 

输出格式:

 

每行一个数,分别是每次询问的结果

 

输入输出样例

输入样例#1:
5
4
x 3 8
y 1 3
x 4 9
y 3 4
输出样例#1:
8
17

 简单的单点更新区间求和

代码:

//编号从1开始
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN=100000;
int n,m,sn,val[MAXN+9],pie[MAXN+9];
void add(int x,int y) { val[x]+=y;pie[x/sn]+=y; }
int query(int x,int y)
{
    int ans=0,xp=(x-1)/sn+1,yp=(y-1)/sn+1;
    for(int i=x;i<=min(xp*sn,y);i++) ans+=val[i];
    if(xp!=yp)
        for(int i=(yp-1)*sn+1;i<=y;i++) ans+=val[i];
    for(int i=xp+1;i<=yp-1;i++) ans+=pie[i];
    return ans;
}
int main()
{
    memset(val,0,sizeof(val));
    memset(pie,0,sizeof(pie));
    scanf("%d%d",&n,&m);
    sn=sqrt(n);
    char ch[2];
    int x,y;
    while(m--){
        scanf("%s%d%d",ch,&x,&y);
        if(ch[0]=='x') add(x,y);
        else printf("%d\n",query(x,y));
    }
    return 0;
}
View Code

 

LightOj 1164

1164 - Horrible Queries
Time Limit: 2 second(s) Memory Limit: 64 MB

World is getting more evil and it's getting tougher to get into the Evil League of Evil. Since the legendary Bad Horse has retired, now you have to correctly answer the evil questions of Dr. Horrible, who has a PhD in horribleness (but not in Computer Science). You are given an array of n elements, which are initially all 0. After that you will be given q commands. They are -

  1. 0 x y v - you have to add v to all numbers in the range of x to y (inclusive), where x and y are two indexes of the array.
  2. 1 x y - output a line containing a single integer which is the sum of all the array elements between x and y (inclusive).

The array is indexed from 0 to n - 1.

Input

Input starts with an integer T (≤ 5), denoting the number of test cases.

Each case contains two integers n (1 ≤ n ≤ 105) and q (1 ≤ q ≤ 50000). Each of the next q lines contains a task in one of the following form:

0 x y v (0 ≤ x ≤ y < n, 1 ≤ v ≤ 1000)

1 x y (0 ≤ x ≤ y < n)

Output

For each case, print the case number first. Then for each query '1 x y', print the sum of all the array elements between x and y.

Sample Input

Output for Sample Input

2

10 5

0 0 9 10

1 1 6

0 3 7 2

0 4 5 1

1 5 5

20 3

0 10 12 1

1 11 12

1 19 19

Case 1:

60

13

Case 2:

2

0

Note

Dataset is huge. Use faster i/o methods.

 题意:

0 x y z 表示x~y区间每个数加z

1 x y 表示询问区间和

最初每个点初值为0

代码:

//区间更新,区间求和。
//这题的询问变成了区间上的询问,不完整的块还是暴力;而要想快速统计完整块的答案,需要维护每个块的元素和,
//先要预处理一下。
//考虑区间修改操作,不完整的块直接改,顺便更新块的元素和;完整的块类似之前标记的做法,
//直接根据块的元素和所加的值计算元素和的增量。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int MAXN=100000;
int t,n,m,sn;
ll val[MAXN+9],tag[MAXN+9],sum[MAXN+9];
void add(int x,int y,int z)
{
    int xb=(x-1)/sn+1,yb=(y-1)/sn+1;
    for(int i=x;i<=min(xb*sn,y);i++) val[i]+=z,sum[xb]+=z;
    if(xb!=yb)
        for(int i=(yb-1)*sn+1;i<=y;i++) val[i]+=z,sum[yb]+=z;
    for(int i=xb+1;i<=yb-1;i++) tag[i]+=z;
}
ll query(int x,int y)
{
    int xb=(x-1)/sn+1,yb=(y-1)/sn+1;
    ll ans=0;
    for(int i=x;i<=min(xb*sn,y);i++) ans+=val[i]+tag[xb];
    if(xb!=yb)
        for(int i=(yb-1)*sn+1;i<=y;i++) ans+=val[i]+tag[yb];
    for(int i=xb+1;i<=yb-1;i++) ans+=tag[i]*sn+sum[i];
    return ans;
}
int main()
{
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        printf("Case %d:\n",cas);
        scanf("%d%d",&n,&m);
        sn=sqrt(n);
        memset(val,0,sizeof(val));
        memset(tag,0,sizeof(tag));
        memset(sum,0,sizeof(sum));
        int p,x,y,z;
        while(m--){
            scanf("%d",&p);
            if(p==0){
                scanf("%d%d%d",&x,&y,&z);
                add(x+1,y+1,z);
            }else{
                scanf("%d%d",&x,&y);
                printf("%lld\n",query(x+1,y+1));
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2017-10-19 20:48  luckilzy  阅读(294)  评论(0编辑  收藏  举报