HDU 4893 Wow! Such Sequence! (线段树)

Wow! Such Sequence!

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 838    Accepted Submission(s): 245

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。

/*************************************************************************
	> File Name: 1007.cpp
	> Author: Bslin
	> Mail: [email protected]
	> Created Time: 2014年07月29日 星期二 13时07分08秒
 ************************************************************************/

#include <cstdio>
#include <cmath>
using namespace std;
#define N 100010

struct node {
	int L, R;
	long long sum, vsum;
	int flag;
} tree[N << 2];
long long ans;

long long ffib(long long val) {
	long long x = 0, y = 1;
	int i;
	for (i = 0; i < 100; ++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 p) {
	if(tree[p].L == tree[p].R) return;
	tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
	tree[p].vsum = tree[p << 1].vsum + tree[p << 1 | 1].vsum;
}

void PushDown(int p) {
	if(tree[p].flag && tree[p].L == tree[p].R) {
		tree[p].sum = tree[p].vsum;
		tree[p].flag = 0;
		return ;
	}
	if(tree[p].flag) {
		tree[p << 1].flag = tree[p << 1 | 1].flag = 1;
		tree[p << 1].sum = tree[p << 1].vsum;
		tree[p << 1 | 1].sum = tree[p << 1 | 1].vsum;
		tree[p].flag = 0;
	}
}

void build(int L, int R, int p) {
	tree[p].L = L;
	tree[p].R = R;
	tree[p].flag = 0;
	if(L == R) {
		tree[p].sum = 0;
		tree[p].vsum = 1;
		return ;
	}
	int mid = (L + R) >> 1;
	build(L, mid, p << 1);
	build(mid + 1, R, p << 1 | 1);
	PushUP(p);
}

void add(int pos, int val, int p) {
	if (tree[p].L == tree[p].R) {
		tree[p].sum += val;
		tree[p].vsum = ffib(tree[p].sum);
		tree[p].flag = 0;
		return ;
	}
	PushDown(p);
	int mid = (tree[p].L + tree[p].R) >> 1;
	if (mid >= pos) add(pos, val, p << 1);
	else add(pos, val, p << 1 | 1);
	PushUP(p);
}

void update(int L, int R, int p) {
	if (L <= tree[p].L && R >= tree[p].R) {
		tree[p].flag = 1;
		tree[p].sum = tree[p].vsum;
		return ;
	}
	PushDown(p);
	int mid = (tree[p].L + tree[p].R) >> 1;
	if (mid >= R) update(L, R, p << 1);
	else if (mid + 1 <= L) update(L, R, p << 1 | 1);
	else {
		update(L, mid, p << 1);
		update(mid + 1, R, p << 1 | 1);
	}
	PushUP(p);
}

void query(int L, int R, int p) {
	if (L <= tree[p].L && R >= tree[p].R) {
		ans += tree[p].sum;
		return ;
	}
	PushDown(p);
	int mid = (tree[p].L + tree[p].R) >> 1;
	if (mid >= R) query(L, R, p << 1);
	else if (mid + 1 <= L) query(L, R, p << 1 | 1);
	else {
		query(L, mid, p << 1);
		query(mid + 1, R, p << 1 | 1);
	}
	PushUP(p);
}

int main(int argc, char *argv[]) {
	freopen("in.txt", "r", stdin);
	int n, m, i;
	int op, x, y;
	while(scanf("%d%d", &n, &m) != EOF) {
		build(1, n, 1);
		for (i = 0; i < m; ++i) {
			scanf("%d%d%d", &op, &x, &y);
			if(op == 1) {
				add(x, y, 1);
			} else if(op == 2) {
				ans = 0;
				query(x, y, 1);
				printf("%I64d\n", ans);  // hdu
			} else if(op == 3) {
				update(x, y, 1);
			}
		}
	}
	return 0;
}

HDU 4893 Wow! Such Sequence! (线段树)

时间: 2024-11-29 01:27:50

HDU 4893 Wow! Such Sequence! (线段树)的相关文章

hdu 4893 Wow! Such Sequence!(线段树)

题目链接:hdu 4983 Wow! Such Sequence! 题目大意:就是三种操作 1 k d, 修改k的为值增加d 2 l r, 查询l到r的区间和 3 l r, 间l到r区间上的所以数变成最近的斐波那契数,相等的话取向下取. 解题思路:线段树,对于每个节点新增一个bool表示该节点以下的位置是否都是斐波那契数. #include <cstdio> #include <cstring> #include <cstdlib> #include <algor

HDU 4893 Wow! Such Sequence 线段树暴力

题意:n个数 初始为0,三个操作:给某个数加上d,查询区间和,把区间[l,r]中每个a[i]变为离a[i]最近的斐波那契数,n,m<=1e5. 无操作1情况下,每个点最多变化一次,每次修改logn,算上操作1 最坏情况下修改n+m次 O((n+m)logn). 对区间设个标记 线段树暴力即可. #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int

HDOJ 4893 Wow! Such Sequence! 线段树

http://acm.hdu.edu.cn/showproblem.php?pid=4893 题意:10万的区间,初始都为0,10万次操作,三种操作为单点修改,区间将每个数改成最近的斐波那契数,以及区间求和. 分析:用一个flag记录该段是否被改成斐波那契数,同时多维护一个sum1表示如果该段改成斐波那契数,区间和为多少.开始sum1为区间长度,之后在单点做了修改以后对其更新,需要的时候用其覆盖sum. 1 #include<cstdio> 2 #include<cstring>

hdu 4893 (多校1007)Wow! Such Sequence!(线段树&amp;二分&amp;思维)

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 352    Accepted Submission(s): 104 Problem Description Recently, Doge got a funny birthday present from his new friend, Prot

HDU 4893 Wow! Such Sequence! 水线段树

思路: 线段树走起.. 写完这题就退役T^T 单点更新的时候直接找到这个点的最近fib,然后维护当前和 和 fib的和 #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> #include<algorithm> #include<queue> #include<map> #include<set> #include&l

hdu 4893 Wow! Such Sequence!(线段树功能:单点更新,区间更新相邻较小斐波那契数)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 --------------------------------------------------------------------------------------------------------------------------------------------

线段树 + 区间更新: HDU 4893 Wow! Such Sequence!

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2234    Accepted Submission(s): 657 Problem Description Recently, Doge got a funny birthday present from his new friend, Prot

2014多校3 Wow! Such Sequence!线段树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 这题实在是让人纠结啊--好久不写线段树的题了,因为这几天学伸展树,然后觉得线段树小case了.没想到栽在这题上了.尼玛-- 自己把自己给搞晕了--想复杂了,都不懂得预处理一下,唉--还得怒刷几十道啊!! #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #in

HDU4893 Wow! Such Sequence! 线段树

题意:给你一个序列,其中有三种操作 1)位置为K 的数+ D 2)求 l-r 区间和 3)把 l-r 区间里面的所有数都变为理它最近的斐波纳契数 解题思路:这个题的区间更新其实可以在单点更新的时候就得出,为节点维护两个 和,一个是 斐波纳契和 一个是正常和 ,再看这个区间有没有被3覆盖,特判一下就行了. 解题代码: 1 // File Name: 1007.cpp 2 // Author: darkdream 3 // Created Time: 2014年07月29日 星期二 12时49分33