POJ 3468 A Simple Problem with Integers (splay tree入门)
Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 47944 | Accepted: 14122 | |
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 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 A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+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
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 }