Wow! Such Sequence!

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2067    Accepted Submission(s): 619

Problem Description
Recently, Doge got a funny birthday present from his new friend,
Protein Tiger from St. Beeze College. No, not cactuses. It's a
mysterious blackbox.

After some research, Doge found that the
box is maintaining a sequence an of n numbers internally, initially all
numbers are zero, and there are THREE "operations":

1.Add d to the k-th number of the sequence.
2.Query the sum of ai where l ≤ i ≤ r.
3.Change ai to the nearest Fibonacci number, where l ≤ i ≤ r.
4.Play sound "Chee-rio!", a bit useless.

Let F0 = 1,F1 = 1,Fibonacci number Fn is defined as Fn = Fn - 1 + Fn - 2 for n ≥ 2.

Nearest Fibonacci number of number x means the smallest Fn where |Fn - x| is also smallest.

Doge doesn't believe the machine could respond each request in less than 10ms. Help Doge figure out the reason.

 
Input
Input contains several test cases, please process till EOF.
For each test case, there will be one line containing two integers n, m.
Next m lines, each line indicates a query:

1 k d - "add"
2 l r - "query sum"
3 l r - "change to nearest Fibonacci"

1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000, |d| < 231, all queries will be valid.

 
Output
For each Type 2 ("query sum") operation, output one line containing an integer represent the answer of this query.
 
Sample Input
1 1
2 1 1
5 4
1 1 7
1 3 17
3 2 4
2 1 5
 
Sample Output
0
22
 
 

题意:

题目中说对一个长度为n,初始元素都为0的数组进行三种操作,如下:

1 k d   第 k 个元素加上 d
2 l r     求从 l 到 r 所有元素的和
3 l r     改变从 l 到 r 所有元素,都为原元素最近的 Fibonacci 数,差值相等时取较小值

思路:

对于第一个操作需要用到线段树中的单点更新操作,对于第二个操作需要用到线段树中的区
间求和操作,对于第三个操作需要思考一下,怎么处理才能最快地改变我们需要改变区间的状态。因为对于区间有个求和操作,那么我们会考虑到只需要改变一段区
间的和即可。处理的方案就是提前对每一段的 区间和 都找到相应的 Fibonacci 数作为映射,那么我们要对区间进行第三操作时,只需要将区间做一下标记,然后将这个映射值覆盖到原
区间和 即可。

注意点:

1.注意 pushdown 和 pushup 的使用。

2.注意当访问到叶子节点时最好是返回(return),若不返回那么开大线段树的大小(原为4倍)也行。

3.注意杭电的输出为 %I64。

 
#include <cstdio>
#include <cmath>
using namespace std;
#define N 100010 struct node {
int L, R;
long long sum, vsum;
int flag;
} tree[N << ];
long long ans; long long ffib(long long val) {
long long x = , y = ;
int i;
for (i = ; i < ; ++i) {
y = x + y;
x = y - x;
if(y >= val)
break;
}
if(fabs(y - val) < fabs(x - val))
return y;
return x;
} void pushUp(int root) { ///向上回溯 不断更新区间和
if(tree[root].L == tree[root].R) return;
tree[root].sum = tree[root << ].sum + tree[root << | ].sum;
tree[root].vsum = tree[root << ].vsum + tree[root << | ].vsum;
} void pushDown(int root) { ///向下更新 falg==1更新的时候
if(tree[root].flag && tree[root].L == tree[root].R) {
tree[root].sum = tree[root].vsum; ///.vsum 求和之后对应该点的Fri数
tree[root].flag = ; ///遍历完了
return ;
}
if(tree[root].flag) {
tree[root << ].flag = tree[root << | ].flag = ;
tree[root << ].sum = tree[root << ].vsum;
tree[root << | ].sum = tree[root << | ].vsum;
tree[root].flag = ; ///遍历完了
}
} void build(int L, int R, int root) { ///建树
tree[root].L = L;
tree[root].R = R;
tree[root].flag = ;
if(L == R) {
tree[root].sum = ;
tree[root].vsum = ;
return ;
}
int mid = (L + R) >> ;
build(L, mid, root << );
build(mid + , R, root << | );
pushUp(root); ///递归遍历求和
} void add(int pos, int val, int root) {
if (tree[root].L == tree[root].R) {
tree[root].sum += val;
tree[root].vsum = ffib(tree[root].sum);
tree[root].flag = ;
return ;
}
pushDown(root);
int mid = (tree[root].L + tree[root].R) >> ;
if (mid >= pos) add(pos, val, root << );
else add(pos, val, root << | );
pushUp(root);
} void update(int L, int R, int root) {
if (L <= tree[root].L && R >= tree[root].R) {
tree[root].flag = ;
tree[root].sum = tree[root].vsum;
return ;
}
pushDown(root);
int mid = (tree[root].L + tree[root].R) >> ;
if (mid >= R) update(L, R, root << );
else if (mid + <= L) update(L, R, root << | );
else {
update(L, mid, root << );
update(mid + , R, root << | );
}
pushUp(root);
} void query(int L, int R, int root) {
if (L <= tree[root].L && R >= tree[root].R) {
ans += tree[root].sum;
return ;
}
pushDown(root);
int mid = (tree[root].L + tree[root].R) >> ;
if (mid >= R) query(L, R, root << );
else if (mid + <= L) query(L, R, root << | );
else {
query(L, mid, root << );
query(mid + , R, root << | );
}
pushUp(root);
} int main(int argc, char *argv[]) {
int n, m, i;
int op, x, y;
while(scanf("%d%d", &n, &m) != EOF) {
build(, n, );
for (i = ; i < m; ++i) {
scanf("%d%d%d", &op, &x, &y);
if(op == ) {
add(x, y, );
} else if(op == ) {
ans = ;
query(x, y, );
printf("%I64d\n", ans); // hdu
} else if(op == ) {
update(x, y, );
}
}
}
return ;
}

http://wenku.baidu.com/link?url=Hk-fzFeInk-_Huvwf7CVVQav0XcEmRn7CEIHNraqHpOYWgJrYXpDEmcRxrzkoB9zs5Xx3A_o7Sk3n9Z2IDyPCWeRHINEgiiu4MFNQ98CIqG

HDU 4893 线段树的 点更新 区间求和的更多相关文章

  1. HDU 1166 敌兵布阵(线段树单节点更新 区间求和)

    http://acm.hdu.edu.cn/showproblem.php?pid=1166 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Dere ...

  2. hdu 1166 线段树(单点增减 区间求和)

    Sample Input1101 2 3 4 5 6 7 8 9 10Query 1 3Add 3 6Query 2 7Sub 10 2Add 6 3Query 3 10End Sample Outp ...

  3. HDU 3577 Fast Arrangement ( 线段树 成段更新 区间最值 区间最大覆盖次数 )

    线段树成段更新+区间最值. 注意某人的乘车区间是[a, b-1],因为他在b站就下车了. #include <cstdio> #include <cstring> #inclu ...

  4. POJ 3468 A Simple Problem with Integers(线段树 成段增减+区间求和)

    A Simple Problem with Integers [题目链接]A Simple Problem with Integers [题目类型]线段树 成段增减+区间求和 &题解: 线段树 ...

  5. HDU 1754 I Hate It(线段树之单点更新 区间最值查询)

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  6. hdu 1754 I Hate It(线段树之 单点更新+区间最值)

    I Hate It                                                                             Time Limit: 90 ...

  7. HDU - 1754 线段树-单点修改+询问区间最大值

    这个也是线段树的经验问题,待修改的,动态询问区间的最大值,只需要每次更新的时候,去把利用子节点的信息进行修改即可以. 注意更新的时候区间的选择,需要对区间进行二分. #include<iostr ...

  8. hdu 1754 线段树(单点替换 区间最值)

    Sample Input5 61 2 3 4 5Q 1 5 //1-5结点的最大值U 3 6 //将点3的数值换成6Q 3 4Q 4 5U 2 9Q 1 5 Sample Output5659 # i ...

  9. HDU 1394.Minimum Inversion Number-最小逆序数-完全版线段树(单点增减、区间求和)

    HDU1394.Minimum Inversion Number 这个题求最小逆序数,先建一个空的树,然后每输入一个值,就先查询一下,查询之后,更新线段树,然后遍历一遍,每次将第一个数放到最后之后,减 ...

随机推荐

  1. mysql 多表查询先排序,然后再取分组<mysql 先order by,然后再取group by分组>

    select * from ( select cv.lasttime,cm.mailbox,cv.clientip from `co_user_visitlog` as cv INNER JOIN ` ...

  2. Centos查公网IP地址

    [root@syy ~]# curl icanhazip.com 115.29.208.111

  3. NC 6系分配组织方法

    分配客户的方法 String[] customer = { cuVO.getPk_customer() }; ICustAssignService cs = NCLocator.getInstance ...

  4. linux内socket服务器无法连接windows

    今天在试socket的时候出现了一个问题:问题概述是这样的: 1.linux采用centOS7(mini)版本,虚拟机版本VMware12,网卡设置NAT 2.服务器和客户端都在windows上,通讯 ...

  5. Permutation Sequence LT60

    The set [1,2,3,...,n] contains a total of n! unique permutations. By listing and labeling all of the ...

  6. fmt标签如何计算两个日期之间相隔的天数

    <h2>start -- ${start}</h2><h2>end -- ${end}</h2><fmt:formatDate var=" ...

  7. 2018.11.08 NOIP模拟 班车(倍增+dfs+bit)

    传送门 对于每个点离线处理出向上走2i2^i2i班车到的最上面的点. 然后每个询问(u,v)(u,v)(u,v)先把(u,v)(u,v)(u,v)倍增到刚好走不到lcalcalca的情况(有一个点如果 ...

  8. 1-9-假期训练心得(dp+bfs)

    题目一:传送门 思路:就是简单的bfs,注意仔细审题,加上对转弯次数的判断. 题目二:传送门 思路:简单dp,记录每一秒每个位置接到的大饼的数量. 状态转移方程:dp[i][j]=max(dp[i][ ...

  9. mac os 卸载android studio 从新安装遇到的一些问题

    http://blog.csdn.net/elonspace/article/details/51800949 google中国论坛 http://www.android-studio.org lin ...

  10. java Concurrent包学习笔记(一):ExecutorService

    一.介绍 ExecutorService是java.util.concurrent包中的一个线程池实现接口.其有两个实现类: 1)ThreadPoolExecutor:普通线程池通过配置线程池大小,能 ...