hdu1166(线段树单点更新、查询)

题目链接: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 }

体会:

  线段树的入门题,加深对线段树的理解和熟悉一下相关操作的代码编写。

posted @ 2018-07-25 12:34  Piccolo_Devil  阅读(450)  评论(0编辑  收藏  举报