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

HDU 4893 Wow! Such Sequence!

题目链接

题意:给定一个序列,3种操作,单点添加值,查询区间和,把区间和变成最接近的婓波那契数

思路:线段树,就是第三个操作麻烦,就在结点添加一个值,标记它区间是不是都是婓波那契数了,然后修改区间的时候,如果区间是了就不用修改,如果不是就继续往后一层推即可

代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>

#define lson(x) ((x<<1) + 1)
#define rson(x) ((x<<1) + 2)

typedef __int64 ll;

const ll INF = 2000000000000000LL;
const int N = 100005;

int n, m, fn;
ll Fib[100];

struct Node {
    int l, r;
    ll sum;
    bool isFib;
} node[4 * N];

void pushup(int x) {
    int l = lson(x);
    int r = rson(x);
    node[x].l = node[l].l; node[x].r = node[r].r;
    node[x].isFib = (node[l].isFib && node[r].isFib);
    node[x].sum = node[l].sum + node[r].sum;
}

void build(int l, int r, int x) {
    if (l == r) {
	node[x].l = l;
	node[x].r = r;
	node[x].sum = 0;
	node[x].isFib = false;
	return;
    }
    int mid = (l + r) / 2;
    build(l, mid, lson(x));
    build(mid + 1, r, rson(x));
    pushup(x);
}

ll abss(ll x) {
    if (x < 0) return -x;
    return x;
}

ll find(ll x) {
    int l = 0, r = fn;
    while (l < r) {
	int mid = (l + r) / 2;
	if (Fib[mid] < x) l = mid + 1;
	else r = mid;
    }
    if (l == 0) return Fib[0];
    ll ll = Fib[l - 1], rr = Fib[l];
    if (abss(x - ll) <= abss(x - rr))
	return ll;
    else return rr;
}

void add(int k, ll v, int x) {
    if (node[x].l == k && node[x].r == k) {
	node[x].sum += v;;
	node[x].isFib = (find(node[x].sum) == node[x].sum);
	return;
    }
    int mid = (node[x].l + node[x].r) / 2;
    if (k <= mid) add(k, v, lson(x));
    if (k > mid) add(k, v, rson(x));
    pushup(x);
}

void insert(int l, int r, int x) {
    if (node[x].isFib) return;

    if (node[x].l == node[x].r) {
	node[x].sum = find(node[x].sum);
	node[x].isFib = true;
	return;
    }

    int mid = (node[x].l + node[x].r) / 2;
    if (l <= mid) insert(l, r, lson(x));
    if (r > mid) insert(l, r, rson(x));
    pushup(x);
}

ll query(int l, int r, int x) {
    if (node[x].l >= l && node[x].r <= r)
	return node[x].sum;
    int mid = (node[x].l + node[x].r) / 2;
    ll ans = 0;
    if (l <= mid) ans += query(l, r, lson(x));
    if (r > mid) ans += query(l, r, rson(x));
    return ans;
}

int main() {
    Fib[0] = Fib[1] = 1;
    for (fn = 2; ; fn++) {
	Fib[fn] = Fib[fn - 2] + Fib[fn - 1];
	if (Fib[fn] > INF) break;
    }
    while (~scanf("%d%d", &n, &m)) {
	build(1, n, 0);
	int Q, a, b;
	ll v;
	while (m--) {
	    scanf("%d", &Q);
	    if (Q == 1) {
		scanf("%d%I64d", &a, &v);
		add(a, v, 0);
	    }
	    else if (Q == 2) {
		scanf("%d%d", &a, &b);
		printf("%I64d\n", query(a, b, 0));
	    }
	    else {
		scanf("%d%d", &a, &b);
		insert(a, b, 0);
	    }
	}
    }
    return 0;
}

HDU Wow! 4893 Such Sequence!(线段树),布布扣,bubuko.com

时间: 2024-12-28 20:12:59

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

HDU 5828 Rikka with Sequence (线段树+剪枝优化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5828 给你n个数,三种操作.操作1是将l到r之间的数都加上x:操作2是将l到r之间的数都开方:操作3是求出l到r之间的和. 操作1和3就不说了,关键是开方操作. 一个一个开方,复杂度太高,无疑会T.所以我们来剪枝一下. 我们可以观察,这里一个数最多开方4,5次(loglogx次)就会到1,所以要是一段区间最大值为1的话,就不需要递归开方下去了.这是一个剪枝. 如果一段区间的数都是一样大小(最大值等于

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 (多校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

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>

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

HDU4893:Wow! Such Sequence!(线段树lazy)

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 nu

hdu 4902 Nice boat(线段树区间修改,输出最终序列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 Problem Description There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his peopl

hdu 1754 I Hate It 线段树 点修改

// hdu 1754 I Hate It 线段树 点修改 // // 不多说,裸的点修改 // // 继续练 #include <algorithm> #include <bitset> #include <cassert> #include <cctype> #include <cfloat> #include <climits> #include <cmath> #include <complex> #i