Description

有一个N个整数的序列(每个数的初值为0)。每个数都是整数。你有M次操作。操作有两种类型:

——Add  Di  Xi 从第一个数开始每隔Di 个位置增加Xi

——Query Li  Ri 回答当前序列Li项到Ri项的和

Input

两个数N和M,输入到文件结尾。以下M行每行的输入两种操作形式的一种。(1 <= N, M, Di, Xi, Li, Ri <= 100000, Li <= Ri )

Output

对于每组数据,输出每组的询问的结果。

Sample Input

4 4
Query 2 3
Add 1 1
Query 2 3
Query 1 4

Sample Output

0
2
4

HINT

Source


这道题出自2013年国家队候选队员罗剑桥的论文《浅谈分块思想在一类数据处理问题中的应用》,是罗原创的一道题。

这道题的解法是分块:

将整个区间从左往右每$\lceil\sqrt{n}\rceil$个分成一块。

更新:

将$ADD\quad D \ X$操作分成两类

  1.   $D \ge \lceil\sqrt{n} \rceil$ 的$ADD$操作,直接更新序列相应位置上元素,并更新各元素所属块由这类$ADD$操作所贡献的和,复杂度是$O(\sqrt{n})$。
  2. $D < \lceil \sqrt{n} \rceil$ 的$ADD$操作,我们将它记录在数组$sum[1\dots\lceil \sqrt{n} \rceil -1]$上:即对于$ADD \quad D \ X$,将$X$累加在$sum[D]$上,复杂度是$O(1)$。

查询:

对于查询区间$[L, R]$,分别查询上述两类$ADD$操作对$[L, R]$的贡献,相加即是答案。


Implementation:

这题我调了很长时间,先贴上第一版(有bug)代码

#include <bits/stdc++.h>
using namespace std; typedef long long LL;
const int N(1e5+);
int n, m, b;
LL bucket[N], sum[N], a[N];
char op[]; inline int ID(int x, int b){ //x>=0
return x? (x-)/b+: ;
} int main(){
for(int T=; ~scanf("%d%d", &n, &m); T++){
if(T==) for(;;);
memset(a, , sizeof(a));
memset(bucket, , sizeof(bucket));
memset(sum, , sizeof(sum));
b=sqrt(n);
for(int d, x, l, r; m--; ){
scanf("%s", op);
if(*op=='A'){
scanf("%d%d", &d, &x);
if(d>=b){
for(int i=; i<=n; i+=d)
a[i]+=x, bucket[ID(i, b)]+=x;
}
else sum[d]+=x;
}
else{
scanf("%d%d", &l, &r);
LL res=;
int L=ID(l-, b)+, R=ID(r+, b)-; //error-prone
////////////////////////////////////////
for(int i=l; i<=b*(L-); i++) res+=a[i];
for(int i=b*R+; i<=r; i++) res+=a[i];
////////////////////////////////////////
for(int i=L; i<=R; i++) res+=bucket[i];
for(int i=; i<b; i++){
res+=(ID(r, i)-ID(l-, i))*sum[i];
}
printf("%lld\n", res);
}
}
}
return ;
}

bug就在分离出来的那两行,坑暂时留着,以后填。

bug-free version

#include <bits/stdc++.h>
using namespace std; typedef long long LL;
const int N(1e5+);
int n, m, b, id[N];
LL bucket[N], sum[N], a[N];
char op[]; LL SUM(int x){
LL res=;
int R=id[x+]-;
for(int i=; i<=R; i++) res+=bucket[i];
for(int i=R*b+; i<=x; i++) res+=a[i];
for(int i=; i<b; i++) res+=((x-)/i+)*sum[i];
return res;
} int main(){
for(; ~scanf("%d%d", &n, &m); ){
memset(a, , sizeof(a));
memset(bucket, , sizeof(bucket));
memset(sum, , sizeof(sum));
b=sqrt(n);
for(int i=; i<=n+; i++) id[i]=(i-)/b+;
for(int d, x, l, r; m--; ){
scanf("%s", op);
if(*op=='A'){
scanf("%d%d", &d, &x);
if(d>=b) for(int i=; i<=n; i+=d) a[i]+=x, bucket[id[i]]+=x;
else sum[d]+=x;
}
else scanf("%d%d", &l, &r), printf("%lld\n", SUM(r)-SUM(l-));
}
}
return ;
}

DLUTOJ #1306 Segment Tree?的更多相关文章

  1. BestCoder#16 A-Revenge of Segment Tree

    Revenge of Segment Tree Problem Description In computer science, a segment tree is a tree data struc ...

  2. [LintCode] Segment Tree Build II 建立线段树之二

    The structure of Segment Tree is a binary tree which each node has two attributes startand end denot ...

  3. [LintCode] Segment Tree Build 建立线段树

    The structure of Segment Tree is a binary tree which each node has two attributes start and end deno ...

  4. Segment Tree Modify

    For a Maximum Segment Tree, which each node has an extra value max to store the maximum value in thi ...

  5. Segment Tree Query I & II

    Segment Tree Query I For an integer array (index from 0 to n-1, where n is the size of this array), ...

  6. Segment Tree Build I & II

    Segment Tree Build I The structure of Segment Tree is a binary tree which each node has two attribut ...

  7. Lintcode: Segment Tree Query II

    For an array, we can build a SegmentTree for it, each node stores an extra attribute count to denote ...

  8. Lintcode: Segment Tree Modify

    For a Maximum Segment Tree, which each node has an extra value max to store the maximum value in thi ...

  9. Lintcode: Segment Tree Query

    For an integer array (index from 0 to n-1, where n is the size of this array), in the corresponding ...

随机推荐

  1. Android 动态加载 (一) 态加载机制 案例一

    在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...

  2. Android SQLite (二) 基本用法

    在Android开发中SQLite起着很重要的作用,网上SQLite的教程有很多很多,不过那些教程大多数都讲得不是很全面.本人总结了一些SQLite的常用的方法,借着论坛的大赛,跟大家分享分享的. 一 ...

  3. php安全配置记录

    Php环境部署完成后,通常我们会进行一些安全设置.除了熟悉各种PHP漏洞外,还可以通过配置php.ini来加固PHP的运行环境.PHP官方也曾经多次修改php.ini的默认设置. 接下来,推荐php. ...

  4. kvm虚拟机时间修改

    在虚拟化环境中,虚拟机在长时间运行过程中,时间会变慢,通常的作法是配置ntpdate定时与时间服务器进行时间同步的计划任务.KVM虚拟机默认采用utc时间,需要专门修改,以及考虑kvm时间同步问题.1 ...

  5. JQuery[一] 中如何选中$(this)下面的子元素

    <ul> li><span></span></li> li><span></span></li> < ...

  6. 对window的认识

    首先要明确: 不管是全局的函数还是全局的变量,都是属于window的,例如: a = 12; //全局变量 alert(a) === alert(window.a) function show(){ ...

  7. cisco交换技术list

  8. Activiti系列:是否可以让某些流程的信息写到历史表,而另外一些不写?

    一.起因     打算使用activiti的定时启动事件来定时启动流程,然后再在该流程中针对每个用户启动另外一个流程实例来计算每个用户的实时账单,系统的用户数一般是1000~2000(此处假设是200 ...

  9. [CareerCup] 2.7 Palindrome Linked List 回文链表

    2.7 Implement a function to check if a linked list is a palindrome. LeetCode上的原题,参见我之前的博客Palindrome ...

  10. LeetCode 334 Increasing Triplet

    这个题是说看一个没有排序的数组里面有没有三个递增的子序列,也即: Return true if there exists i, j, k such that arr[i] < arr[j] &l ...