hdu-4893-Wow! Such Sequence!-线段树【2014多校第三场-J】

题意:一个初始为0的数组,支持三种操作:1、向第k个数添加d,(|d| < 2^31);2、把[l, r]区间内的数字都换成与它最相近的Fibonacci数;3、询问[l, r]区间的和。

思路:初始化Fibonacci数组,longlong 类型内90个就够用了。

  线段树区间查询,用lazy标记, sgt[]记录线段树各个节点的区间和, fib_num_sum[]记录与各个叶子节点当前值最接近的Fibonacci数,传递到区间fib_num_sum[]就是区间Fibonacci数的和。

  操作1时第k个数的sgt[]+= d,同时更新fib_num_sum[]。操作2即把找到的区间sgt[]=fib_num_sum[]。操作3,直接返回区间sgt[]值。

AC代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 using namespace std;
  5 #define maxn 100005
  6 #define lson l, m, rt<<1
  7 #define rson m+1, r, rt<<1|1
  8 long long sgt[maxn<<2], fib_num_sum[maxn<<2];
  9 bool lazy[maxn<<2];
 10 long long fib[100];
 11 void init_fib()
 12 {
 13    fib[0] = fib[1] = 1;
 14    for(int i = 2; i < 92; i++){
 15       fib[i] = fib[i-1] + fib[i-2];
 16    }
 17 }
 18 
 19 void push_up(int rt)
 20 {
 21    sgt[rt] = sgt[rt<<1] + sgt[rt<<1|1];
 22    fib_num_sum[rt] = fib_num_sum[rt<<1] + fib_num_sum[rt<<1|1];
 23 }
 24 
 25 void push_down(int rt)
 26 {
 27    if(lazy[rt]){
 28       lazy[rt<<1] = lazy[rt<<1|1] = 1;
 29       lazy[rt] = 0;
 30       sgt[rt<<1] = fib_num_sum[rt<<1];
 31       sgt[rt<<1|1] = fib_num_sum[rt<<1|1];
 32    }
 33 }
 34 
 35 long long find_fib(long long x)
 36 {
 37    int a = lower_bound(fib, fib+92, x) - fib;
 38    if(x && fib[a] - x >= x - fib[a-1]) return fib[a-1];
 39    return fib[a];
 40 }
 41 
 42 void build(int l, int r, int rt)
 43 {
 44    lazy[rt] = 0, fib_num_sum[rt] = 1;
 45    if(l == r){
 46       sgt[rt] = 0;
 47       return;
 48    }
 49    int m = (r + l) >>1;
 50    build(lson);
 51    build(rson);
 52    push_up(rt);
 53 }
 54 void add(int l, int r, int rt, int k, int d)
 55 {
 56    if(l == r) {
 57       sgt[rt] += d;
 58       fib_num_sum[rt] = find_fib(sgt[rt]);
 59       return;
 60    }
 61    push_down(rt);
 62    int m = (l+r)>>1;
 63    if(m >= k) add(lson, k, d);
 64    if(m < k) add(rson, k, d);
 65    push_up(rt);
 66 }
 67 
 68 void change(int l, int r, int rt, int L, int R)
 69 {
 70    if(L <= l&&r <= R){
 71       lazy[rt] = 1;
 72       sgt[rt] = fib_num_sum[rt];
 73       return;
 74    }
 75    push_down(rt);
 76    int m = (r+l)>>1;
 77    if(L <= m) change(lson, L, R);
 78    if(m < R) change(rson, L, R);
 79    push_up(rt);
 80 }
 81 
 82 long long query(int l, int r, int rt, int L, int R)
 83 {
 84    if(L <= l&&r <= R) return sgt[rt];
 85    push_down(rt);
 86    int m = (r+l)>>1;
 87    long long ans = 0;
 88    if(L <= m) ans += query(lson, L, R);
 89    if(m < R) ans += query(rson, L, R);
 90    return ans;
 91 }
 92 
 93 int n, m;
 94 void work()
 95 {
 96    build(1, n, 1);
 97    while(m--){
 98       int a; scanf("%d", &a);
 99       if(a == 1) {
100          int k, d; scanf("%d%d", &k, &d);
101          add(1, n, 1, k, d);
102       }
103       if(a == 2) {
104          int l, r; scanf("%d%d", &l, &r);
105          printf("%I64d\n", query(1, n, 1, l, r));
106       }
107       if(a == 3) {
108          int l, r; scanf("%d%d", &l, &r);
109          change(1, n, 1, l, r);
110       }
111    }
112 }
113 
114 int main()
115 {
116    init_fib();
117    while(scanf("%d%d", &n, &m) != EOF) work();
118    return 0;
119 }
View Code

 

转载于:https://www.cnblogs.com/ZiningTang/p/3879734.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值