POJ 3468 A Simple Problem with Integers (splay tree入门)

A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 47944 Accepted: 14122
Case Time Limit: 2000MS

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

 
 
 
 
 
 
 
 
  1 /* ***********************************************
  2 Author        :kuangbin
  3 Created Time  :2013/8/24 22:13:15
  4 File Name     :F:\2013ACM练习\专题学习\splay_tree_2\POJ3468.cpp
  5 ************************************************ */
  6 
  7 #include <stdio.h>
  8 #include <string.h>
  9 #include <iostream>
 10 #include <algorithm>
 11 #include <vector>
 12 #include <queue>
 13 #include <set>
 14 #include <map>
 15 #include <string>
 16 #include <math.h>
 17 #include <stdlib.h>
 18 #include <time.h>
 19 using namespace std;
 20 //普通的线段树操作,区间增加一个值,查询区间的和
 21 #define Key_value ch[ch[root][1]][0]
 22 const int MAXN = 100010;
 23 int pre[MAXN],ch[MAXN][2],root,tot1;
 24 int size[MAXN];//子树的结点数
 25 int add[MAXN];//增量的延迟标记
 26 int key[MAXN];
 27 long long sum[MAXN];//子树的和
 28 int s[MAXN],tot2;//内存池和容量
 29 int a[MAXN];//初始的数组,建树的时候用,下标从1开始
 30 
 31 //debug部分**********************************
 32 void Treavel(int x)
 33 {
 34     if(x)
 35     {
 36         Treavel(ch[x][0]);
 37         printf("结点:%2d: 左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d add = %2d sum = %I64d\n",x,ch[x][0],ch[x][1],pre[x],size[x],add[x],sum[x]);
 38         Treavel(ch[x][1]);
 39     }
 40 }
 41 void debug()
 42 {
 43     printf("root:%d\n",root);
 44     Treavel(root);
 45 }
 46 //以上是debug部分**************************************
 47 
 48 void NewNode(int &r,int father,int k)
 49 {
 50     if(tot2)r = tot2--;//取的时候是tot2--,存的时候就是++tot2
 51     else r = ++tot1;
 52     pre[r] = father;
 53     size[r] = 1;
 54     add[r] = 0;
 55     key[r] = k;
 56     sum[r] = k;
 57     ch[r][0] = ch[r][1] = 0;
 58 }
 59 //给r为根的子树增加值,把当前结点更新掉,加延迟标记
 60 void Update_Add(int r,int ADD)
 61 {
 62     if(r == 0)return;
 63     add[r] += ADD;
 64     key[r] += ADD;
 65     sum[r] += (long long)ADD*size[r];
 66 }
 67 void push_up(int r)
 68 {
 69     size[r] = size[ch[r][0]] + size[ch[r][1]] + 1;
 70     sum[r] = sum[ch[r][0]] + sum[ch[r][1]] + key[r];
 71 }
 72 void push_down(int r)
 73 {
 74     if(add[r])
 75     {
 76         Update_Add(ch[r][0],add[r]);
 77         Update_Add(ch[r][1],add[r]);
 78         add[r] = 0;
 79     }
 80 }
 81 //建树
 82 void Build(int &x,int l,int r,int father)
 83 {
 84     if(l > r)return;
 85     int mid = (l+r)/2;
 86     NewNode(x,father,a[mid]);
 87     Build(ch[x][0],l,mid-1,x);
 88     Build(ch[x][1],mid+1,r,x);
 89     push_up(x);
 90 }
 91 int n,q;
 92 //初始化
 93 void Init()
 94 {
 95     root = tot1 = tot2 = 0;
 96     ch[root][0] = ch[root][1] = pre[root] = size[root] = add[root] = sum[root] = key[root] = 0;
 97     //加两个虚结点
 98     NewNode(root,0,-1);
 99     NewNode(ch[root][1],root,-1);
100     for(int i = 1;i <= n;i++)
101         scanf("%d",&a[i]);
102     Build(Key_value,1,n,ch[root][1]);
103     push_up(ch[root][1]);
104     push_up(root);
105 }
106 //旋转,0为左旋,1为右旋
107 void Rotate(int x,int kind)
108 {
109     int y = pre[x];
110     push_down(y);
111     push_down(x);//先把y的标记下传,在把x的标记下传
112     ch[y][!kind] = ch[x][kind];
113     pre[ch[x][kind]] = y;
114     if(pre[y])
115         ch[pre[y]][ch[pre[y]][1]==y] = x;
116     pre[x] = pre[y];
117     ch[x][kind] = y;
118     pre[y] = x;
119     push_up(y);
120 }
121 //Splay调整,将r结点调整到goal下面
122 void Splay(int r,int goal)
123 {
124     push_down(r);
125     while(pre[r] != goal)
126     {
127         if(pre[pre[r]] == goal)
128             Rotate(r,ch[pre[r]][0]==r);
129         else
130         {
131             int y = pre[r];
132             int kind = ch[pre[y]][0]==y;
133             if(ch[y][kind] == r)
134             {
135                 Rotate(r,!kind);
136                 Rotate(r,kind);
137             }
138             else
139             {
140                 Rotate(y,kind);
141                 Rotate(r,kind);
142             }
143         }
144     }
145     push_up(r);
146     if(goal == 0) root = r;
147 }
148 //得到第k个结点
149 int Get_kth(int r,int k)
150 {
151     push_down(r);
152     int t = size[ch[r][0]] + 1;
153     if(t == k)return r;
154     if(t > k)return Get_kth(ch[r][0],k);
155     else return Get_kth(ch[r][1],k-t);
156 }
157 
158 //区间增加一个值
159 //因为加了个空结点,所以将第l个点旋转到根结点,第r+2个点旋转到根结点的右孩子
160 //那么Key_value就是需要修改的区间[l,r]
161 void ADD(int l,int r,int D)
162 {
163     Splay(Get_kth(root,l),0);
164     Splay(Get_kth(root,r+2),root);
165     Update_Add(Key_value,D);
166     push_up(ch[root][1]);
167     push_up(root);
168 }
169 //查询区间的和
170 long long Query_sum(int l,int r)
171 {
172     Splay(Get_kth(root,l),0);
173     Splay(Get_kth(root,r+2),root);
174     return sum[Key_value];
175 }
176 
177 int main()
178 {
179     //freopen("in.txt","r",stdin);
180     //freopen("out.txt","w",stdout);
181     while(scanf("%d%d",&n,&q) == 2)
182     {
183         Init();
184         //debug();
185         int x,y,z;
186         char op[20];
187         while(q--)
188         {
189             scanf("%s",op);
190             if(op[0] == 'Q')
191             {
192                 scanf("%d%d",&x,&y);
193                 printf("%I64d\n",Query_sum(x,y));
194             }
195             else
196             {
197                 scanf("%d%d%d",&x,&y,&z);
198                 ADD(x,y,z);
199             }
200         }
201     }
202     return 0;
203 }

 

 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值