AOJ 902 讨厌的“2” 【线段树】

题面:

有一个长度为n的数组a。现有m组操作。
操作1:将区间[l,r]内的所有数字都整除2。
操作2:输出区间[l,r]内所有数字的和。

Input

第一行输入两个整数n,m(1<=n<=200000,1<=m<=200000)
第二行n个整数,表示数组a (0<=a[i]<=10^9)
接下来m行,每行三个整数op,l,r
——若op=1,表示操作1,将[l,r]内所有数字整除2
——若op=2,表示操作2,输出[l,r]内所有数字的和

Output

对于所有的操作2,输出结果。

Sample Input

5 5

3 4 9 2 7

2 3 4

1 4 5

2 1 5

1 3 4

2 3 5

Sample Output

11

20

7

大致思路:

这个题是不能用lazytag的,因为整除不满足使用lazytag的条件。

比如 对于序列1 3 5 7 9

如果现在要求是 1 1 5

然后求2 1 5

真实答案是 10

如果用lazytag标记的话答案就是12

所以只能进行点修改。

但也有可以优化的地方,如果一个区间的sum已经是0了,那么就没有必要继续递归修改了,因为0/2=0

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=2e5+7;
 4 int a[maxn];
 5 long long sum[maxn<<2];
 6 void maintain(int k)
 7 {
 8     sum[k]=sum[k<<1]+sum[k<<1|1];
 9 }
10 void build(int l,int r,int k)
11 {
12     if(l>r)
13         return ;
14     if(l==r){
15         sum[k]=a[l];
16         return ;
17     }
18     int mid=(l+r)>>1;
19     build(l,mid,k<<1);
20     build(mid+1,r,k<<1|1);
21     maintain(k);
22 }
23 void change(int l,int r,int cl,int cr,int k)
24 {
25     if(sum[k]==0)
26         return ;
27     if(l>r||cl>r||cr<l)
28         return ;
29     if(l==r){
30         sum[k]=sum[k]/2;
31         return ;
32     }
33
34     int mid=(l+r)>>1;
35     change(l,mid,cl,cr,k<<1);
36     change(mid+1,r,cl,cr,k<<1|1);
37     maintain(k);
38 }
39 long long query(int l,int r,int ql,int qr,int k)
40 {
41     if(l>r||ql>r||qr<l)
42         return 0;
43     if(ql<=l&&qr>=r)
44         return sum[k];
45     if(sum[k]==0)
46         return 0;
47     int mid=(l+r)>>1;
48     long long ans=0;
49     ans=+query(l,mid,ql,qr,k<<1);
50     ans+=query(mid+1,r,ql,qr,k<<1|1);
51     return ans;
52 }
53 int main()
54 {
55     ios::sync_with_stdio(false);
56     memset(sum,0,sizeof(sum));
57     int n,m,cmd,l,r;
58     cin>>n>>m;
59     for(int i=1;i<=n;++i)
60         cin>>a[i];
61     build(1,n,1);
62     for(int i=0;i<m;++i){
63         cin>>cmd>>l>>r;
64         if(cmd==1)
65             change(1,n,l,r,1);
66         else
67             cout<<query(1,n,l,r,1)<<endl;
68     }
69     return 0;
70 }
时间: 2024-08-09 19:51:56

AOJ 902 讨厌的“2” 【线段树】的相关文章

【伪题解】线段树什么最讨厌了 (DFS)

Description: 小丫最近学习了线段树,但是由于她的智商比较低,运用的还不是很熟练.于是小R给了她一点练习题训练,其中有一道是这样的.这是小R写的线段树的一段建树代码: 只要调用buildtree(1,0,n)就可以得到一颗线段树了.显然,一颗线段树一共有O(n)个节点,因为每一个节点都代表了一个不同的区间,所以线段树上一共出现了O(n)个不同的区间.现在小R给了你一个区间[l ;r ] ,想要你告诉他一个最小的n使得区间[l ;]出现在了用buildtree(1,0n)建出来的线段树中

POJ 3321 Apple Tree 【树形结构转变为线性结构+线段树OR树状数组】

Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21587   Accepted: 6551 POJ 3321链接: Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so

poj 2828 Buy Tickets 【买票插队找位置 输出最后的位置序列+线段树】

题目地址:http://poj.org/problem?id=2828 Sample Input 4 0 77 1 51 1 33 2 69 4 0 20523 1 19243 1 3890 0 31492 Sample Output 77 33 69 51 31492 20523 3890 19243 Hint The figure below shows how the Little Cat found out the final order of people in the queue d

吊打线段树的超级树状数组

你是否讨厌线段树那冗长的代码?你是否还在因为线段树的难调试而满头♂dark汗?那么,请不要错过!超级树状数组特价!只要998,只要998! ##¥……#……¥%……&%¥……ER#%$#$#^T%$^$% 超级树状数组,其实是一种能够支持区间修改和区间查询的树状数组,和线段树相比,它的常数极小,不需要太多空间,代码量也少了很多(简直吊打线段树) 1.树状数组 既然是超级树状数组,那么就需要一个树状数组作为基础了.但是在真正实现时,只用到了lowbit()函数(所以说lowbit是树状数组的核心啊

luogu4556 雨天的尾巴 (线段树合并+差分)

题目背景 深绘里一直很讨厌雨天.灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切.虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉.无奈的深绘里和村民们只好等待救济粮来维生.不过救济粮的发放方式很特别.题目描述 首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮.然后深绘里想知道,当所有的救济粮发

[树上差分][线段树合并]JZOJ 3397 雨天的尾巴

Description 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连 根拔起,以及田地里的粮食被弄得一片狼藉. 无奈的深绘里和村民们只好等待救济粮来维生. 不过救济粮的发放方式很特别. 首先村落里的一共有n 座房屋,并形成一个树状结构.然后救济粮分m 次发放,每次选择 两个房屋(x,y),然后对于x 到y 的路径上(含x 和y) 每座房子里发放一袋z 类型的救济粮.

P4556 [Vani有约会]雨天的尾巴 树链剖分 线段树合并

P4556 [Vani有约会]雨天的尾巴 提交2.75k 通过789 时间限制1.00s 内存限制125.00MB 提交代码加入收藏 题目提供者yyy2015c01 难度省选/NOI- 历史分数100 提交记录查看题解 标签 查看算法标签 相关讨论 进入讨论版 查看讨论 推荐题目 查看推荐 展开 题目背景 深绘里一直很讨厌雨天.灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切.虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间