题目链接:http://hdu.hustoj.com/showproblem.php?pid=1166
题意:
第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令
思路:
典型的线段树单点更新+查询
代码:
1 #include <iostream> 2 using namespace std; 3 4 const int maxn = 50010; 5 int segTree[maxn * 4]; //1-n子区间数量不超过4*n 6 7 8 void pushUp(int root) //更新父节点值 9 { 10 segTree[root] = segTree[root * 2] + segTree[root * 2 + 1]; //这题的操作是求和 11 } 12 13 void build(int root, int left, int right) //建立线段树 14 { 15 if (left == right) //到了叶子节点就输入叶子结点的值 16 { 17 cin >> segTree[root]; 18 return; 19 } 20 21 int mid = (left + right) / 2; 22 23 //递归建立左子树和右子树 24 build(root * 2, left, mid); 25 build(root * 2 + 1, mid + 1, right); 26 27 //每次更新父节点值 28 pushUp(root); 29 } 30 31 void update(int root, int p, int add, int left, int right) //单节点更新,p为待更新节点下标,add为需增加或减少的值 32 { 33 if (left == right) //找到单节点就更新 34 { 35 segTree[root] += add; 36 return; 37 } 38 39 //二分查找指定节点 40 int mid = (left + right) / 2; 41 if (p <= mid) 42 { 43 update(root * 2, p, add, left, mid); 44 } 45 else 46 { 47 update(root * 2 + 1, p, add, mid + 1, right); 48 } 49 50 //每次更新父节点值 51 pushUp(root); 52 } 53 54 int query(int root, int q_left, int q_right, int now_left, int now_right) //查询区间 55 { 56 if (q_left <= now_left && q_right >= now_right) //当前节点区间包含在查询区间内 57 { 58 return segTree[root]; 59 } 60 61 int mid = (now_left + now_right) / 2; 62 int sum = 0; 63 if (q_left <= mid) 64 { 65 sum += query(root * 2, q_left, q_right, now_left, mid); 66 } 67 if (q_right > mid) 68 { 69 sum += query(root * 2 + 1, q_left, q_right, mid + 1, now_right); 70 } 71 return sum; 72 } 73 74 int main() 75 { 76 ios::sync_with_stdio(false); //取消cin于stdin的同步,不加这句除非用scanf和printf,不然会TLE 77 int t, n; 78 char op[10]; 79 cin >> t; 80 for (int i = 1; i <= t; i++) 81 { 82 cout << "Case " << i << ":" << endl; 83 cin >> n; 84 build(1, 1, n); 85 while(cin >> op) 86 { 87 if (op[0] == 'E') 88 { 89 break; 90 } 91 int a, b; 92 cin >> a >> b; 93 if (op[0] == 'Q') //询问 94 { 95 int ans = query(1, a, b, 1, n); 96 cout << ans << endl; 97 } 98 else if (op[0] == 'S') //减 99 { 100 update(1, a, -b, 1, n); 101 } 102 else if (op[0] == 'A') //加 103 { 104 update(1, a, b, 1, n); 105 } 106 } 107 } 108 return 0; 109 }
体会:
线段树的入门题,加深对线段树的理解和熟悉一下相关操作的代码编写。