zoukankan      html  css  js  c++  java
  • 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: Baoshenglin1994@gmail.com
    	> 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
    ", ans);  // hdu
    			} else if(op == 3) {
    				update(x, y, 1);
    			}
    		}
    	}
    	return 0;
    }
    


  • 相关阅读:
    Java性能小技巧
    使用Gitolite搭建Gitserver
    refresh的停车场(栈和队列的STL)
    BZOJ 2005 NOI2010 能量採集 数论+容斥原理
    PHP第四课 了解经常使用的函数
    JavaScript实现对象数组按不同字段排序
    android之Context对各种服务的管理
    程序员应该阅读的非编程类书籍有哪些?
    是男人就下100层【第五层】——换肤版2048游戏
    是男人就下100层【第四层】——Crazy贪吃蛇(3)
  • 原文地址:https://www.cnblogs.com/mthoutai/p/6773402.html
Copyright © 2011-2022 走看看