【POJ2761】【fhq treap】A Simple Problem with Integers

Description

You have N integers, A1A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.

Source

POJ Monthly--2007.11.25, Yang Yi

【分析】

这个其实是个水题。我只是拿来fhq treap的...

Orzzzzzz范大爷

这种数据结构真是...能保证treap的性质同时也能保证合并后的树还能原封不动的切出来...

说它是treap,我觉得就一个fix像treap而已。

这个数据结构的精髓在合并和分裂(和打标记?)。有注释.

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <vector>
  6 #include <utility>
  7 #include <iomanip>
  8 #include <string>
  9 #include <cmath>
 10 #include <queue>
 11 #include <assert.h>
 12 #include <map>
 13 #include <ctime>
 14 #include <cstdlib>
 15 #define LOCAL
 16 const int MAXN = 100000 + 10;
 17 const int INF = 0x3f3f3f3f;
 18 const int SIZE = 450;
 19 const int maxnode =  1101000;
 20 using namespace std;
 21 typedef long long ll;
 22 ll n, m;
 23 struct fhqTreap{
 24        struct Node{
 25               Node *l, *r;
 26               ll delta, sum;
 27               ll size, fix, val;
 28        }*root, *null, mem[1101000];
 29        ll tot;
 30
 31        ll BIG_RAND(){return (ll)rand()*RAND_MAX + (ll)rand();}
 32        void init(){
 33             tot = 0;
 34             NEW(null, 0);
 35             null->size = 0;
 36             root = null;
 37             insert(0, n);//插入
 38        }
 39        void update(Node *t){
 40             if (t == null) return;
 41             t->size = t->l->size + t->r->size + 1;
 42             t->sum = t->val;
 43             if (t->l != null) t->sum += t->l->sum;
 44             if (t->r != null) t->sum += t->r->sum;
 45        }
 46        //标记下传=-=
 47        void push_down(Node *t){
 48             if (t->delta){
 49                t->val += t->delta;
 50
 51                if (t->l != null) {t->l->delta += t->delta, t->l->sum += t->l->size * t->delta;}
 52                if (t->r != null) {t->r->delta += t->delta, t->r->sum += t->r->size * t->delta;}
 53
 54                t->delta = 0;
 55             }
 56        }
 57
 58        void NEW(Node *&t, ll val){
 59             t = &mem[tot++];
 60             t->size = 1;
 61             t->fix = BIG_RAND();
 62             t->sum = t->val = val;
 63             t->delta = 0;
 64             t->l = t->r = null;
 65        }
 66        //将t分裂为大小p和t->size - p的两个子树
 67        void split(Node *t, Node *&a, Node *&b, int p){
 68             if (t->size <= p) a = t, b = null;
 69             else if (p == 0) a = null, b = t;
 70             else {
 71                  push_down(t);
 72                  if (t->l->size >= p){
 73                     b = t;
 74                     split(t->l, a , b->l, p);
 75                     update(b);
 76                  }else{
 77                     a = t;
 78                     split(t->r, a->r, b, p - t->l->size - 1);
 79                     update(a);
 80                  }
 81             }
 82        }
 83        //将a,b树合并为t
 84        void merge(Node *&t, Node *a, Node *b){
 85             if (a == null) t = b;
 86             else if (b == null) t = a;
 87             else {
 88                  if (a->fix > b->fix){//按fix值排序
 89                     push_down(a);
 90                     t = a;
 91                     merge(t->r, a->r, b);
 92                  }else{
 93                     push_down(b);
 94                     t = b;
 95                     merge(t->l, a, b->l);
 96                  }
 97                  update(t);
 98             }
 99        }
100        void add(ll l, ll r, ll val){
101             Node *a, *b, *c;
102             split(root, a, b, l - 1);
103             split(b, b, c, r - l + 1);
104             b->delta += val;
105             b->sum += val * b->size;
106             merge(a, a, b);
107             merge(root, a, c);
108        }
109        ll query(ll l, ll r){
110           Node *a, *b, *c;
111           split(root, a, b, l - 1);
112           split(b, b, c, r - l + 1);
113           ll ans = b->sum;
114           merge(b, b, c);
115           merge(root, a, b);
116           return ans;
117        }
118        //把b挤出去
119        void Delete(ll p){
120             Node *a, *b, *c;
121             split(root, a, b, p - 1);
122             split(b, b, c, 1);
123             merge(root, a, c);
124        }
125        Node *Insert(ll x){//不可思议的插入方式
126             if (x == 0) return null;
127             if (x == 1){
128                ll tmp;
129                scanf("%lld", &tmp);
130                Node *a;
131                NEW(a, tmp);
132                return a;
133             }
134             Node *a, *b;
135             int mid = x / 2;
136             a = Insert(mid);
137             b = Insert(x - mid);
138             merge(a, a, b);
139             return a;
140        }
141
142        //在pos处插入x个数字
143        void insert(ll pos, ll x){
144             Node *a, *b, *c, *t;
145             //跟块状链表的有点像,分裂再合并
146             split(root, a, b, pos);
147             c = Insert(x);//插入一个值为x的树
148             merge(a, a, c);
149             merge(root, a, b);
150        }
151 }A;
152
153 void work(){
154      char str[3];
155      while (m--){
156            scanf("%s", str);
157            if (str[0] == ‘Q‘){
158               ll l, r;
159               scanf("%lld%lld", &l, &r);
160               printf("%lld\n", A.query(l, r));
161            }else{
162               ll l, r, k;
163               scanf("%lld%lld%lld", &l, &r, &k);
164               A.add(l, r, k);
165            }
166      }
167 }
168
169 int main(){
170
171     while( scanf("%lld%lld", &n, &m) != EOF){
172            A.init();
173            work();
174     }
175     return 0;
176 }

时间: 2024-08-05 00:00:49

【POJ2761】【fhq treap】A Simple Problem with Integers的相关文章

POJ 3468 A Simple Problem with Integers 【树状数组】

题目链接:http://poj.org/problem?id=3468 题目大意:给出一组数组v[i],有两种操作,一种给出两个数a,b,要求输出v[a]到v[b]之间的和,另一种给出三个数a,b,c,让v[a]到v[b]之间的数全都加上c. 完全是树状数组能够实现的功能,但是如果就这样单纯的套用模板,做第二种操作是更新每个值,这样的操作就有可能超时. 换一种思路,既然第二种操作是给某区间上的所有数加上相同的值,那么应该是能够简化的才对. 假设数组sum[i]为原数组从v[1]到v[i]的和,数

POJ3468 A Simple Problem with Integers 【线段树】+【成段更新】

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 57666   Accepted: 17546 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

【POJ】3468 A Simple Problem with Integers ——线段树 成段更新 懒惰标记

A Simple Problem with Integers Time Limit:5000MS   Memory Limit:131072K Case Time Limit:2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each

POJ A Simple Problem with Integers 【线段树,区间更新】

题意:你有N个整数,A1,A2,-,一个.你需要处理两种类型的操作.一种类型的操作是添加了一些给定的数字,每个数字在一个给定的时间间隔.另一种是在给定的时间间隔要求数量的总和. 难点:主要是lazy标记,不好弄懂, 其实lazy标记就是当前改变的值不全部更新,等到用的时候再更新,这样就节省了好多时间. 题目链接:http://poj.org/problem?id=3468 代码: #include<stdio.h> #include<string.h> #define MAXN 1

一本通1548【例 2】A Simple Problem with Integers

1548:[例 2]A Simple Problem with Integers 题目描述 这是一道模板题. 给定数列 a[1],a[2],-,a[n],你需要依次进行 q 个操作,操作有两类: 1 l r x:给定 l,r,x,对于所有 i∈[l,r],将 a[i] 加上 x(换言之,将 a[l],a[l+1],-,a[r] 分别加上 x): 2 l r:给定 l,r,求 a[i]∑i=[l,r].?a[i] 的值(换言之,求 a[l]+a[l+1]+?+a[r] 的值). 输入格式 第一行包

【成端更新线段树模板】POJ3468-A Simple Problem with Integers

http://poj.org/problem?id=3468 _(:зゝ∠)_我又活着回来啦,前段时间太忙了写的题没时间扔上来,以后再说. [问题描述] 成段加某一个值,然后询问区间和. [思路] 讲一下pushdown和pushup出现的几个位置. pushup: (1)build的结尾,当叶子节点分别有对应的值后,它的父亲们就等于它们求和. (2)update的结尾,因为此时当前根的左右孩子已经更新了,故它也需要更新. pushdown(延迟标记): *pushdown会出现在一切要从当前结

【树状数组区间修改单点查询+分组】HDU 4267 A Simple Problem with Integers

http://acm.hdu.edu.cn/showproblem.php?pid=4267 [思路] 树状数组的区间修改:在区间[a, b]内更新+x就在a的位置+x. 然后在b+1的位置-x 树状数组的单点查询:求某点a的值就是求数组中1~a的和. (i-a)%k==0把区间分隔开了,不能直接套用树状数组的区间修改单点查询 这道题的K很小,所以可以枚举k,对于每个k,建立k个树状数组,所以一共建立55棵树 所以就可以多建几棵树..然后就可以转换为成段更新了~~ [AC] 1 #include

【POJ3468】【zkw线段树】A Simple Problem with Integers

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. In

【POJ3468】【树状数组区间修改】A Simple Problem with Integers

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. In