HDU1166:敌兵布阵(线段树以及单点更新)

来源:互联网 发布:数据分析职业发展 知乎 编辑:程序博客网 时间:2024/06/01 03:59

题意: 一个军队有一定数量的军营,这个军营是动态变化的,人数可多可少,经过一系列的操作,询问某个军营的人数。

输入: 第一行是T组数据,下一行有一个正整数N表示有N个军营。接下来进行操作:add  i   j表示在第i个军营增加j个士兵;

sub   i   j表示在第i个军营减少j个士兵query i   j表示查找第i个军营到第j个军营士兵的数目;end 表示结束输入

输出: 每一次query就输出当前区间内的士兵数目,注意输出格式。


这一题直接莽是肯定会wa的,因为多次的询问是肯定超时的。这里使用的是线段树来存贮数据的。


先介绍一下线段树:对于一个区间为1-10来说segTree所做的操作就是不停的二分,segTree这个结构体的下标代表了下图的圆圈序号

这里需要说明的是,下面的24号节点之前没有23节点这是这种数据结构的规定,也就是说segtree这个结构中某些下标里的内容其实是空的。

ps:segtree[3]表示的是区间6-10的内容。



建立树的过程就在下面的代码里面。


修改的过程其实就是二分寻找适当的区间直接进行增减。修改的标志就是左区间和右区间完全重合。这里的递归过程希望能够理解,可以借助debug进行实时跟踪。


询问查找这部分的思想其实跟单点更新的思想差不多,不过需要注意的是因为求解和,所以如果查找的区间恰好在总区间的范围内时将此时的segtree[i]的两个子节点的nsum

进行相加操作。

(这一部分的内容借助debug可以直接发现这个数据结构究竟做了什么事,关键还是理解好这个结构体和数组之间的直接区别)


代码:

[cpp] view plain copy
  1. #include<bits/stdc++.h>  
  2. using namespace std;  
  3. const int MAXN = 50005;  
  4. struct Node  
  5. {  
  6.     int l, r;  
  7.     int nSum;//记录当前人数  
  8. }segTree[MAXN * 4];  
  9.   
  10. int num[MAXN];//存贮初始人数  
  11.   
  12. void Build(int i, int l, int r)  
  13. {  
  14.     segTree[i].l = l;  
  15.     segTree[i].r = r;  
  16.     if (l == r)  
  17.     {  
  18.         segTree[i].nSum = num[l];  
  19.         return;  
  20.     }  
  21.     int mid = (l + r) >> 1;  
  22.     Build(i << 1, l, mid);  
  23.     Build(i << 1 | 1, mid + 1, r);  
  24.     segTree[i].nSum = segTree[i << 1].nSum + segTree[i << 1 | 1].nSum;  
  25.     //cout<<i<<" "<<segTree[i].nSum<<endl;  
  26. }  
  27.   
  28. void Add(int i, int t, int b)  
  29. {  
  30.     segTree[i].nSum += b;  
  31.     if (segTree[i].l == t&&segTree[i].r == t)  
  32.         return;  
  33.     int mid = (segTree[i].l + segTree[i].r) >> 1;  
  34.     if (t <= mid)  
  35.         Add(i << 1, t, b);  
  36.     else  
  37.         Add(i << 1 | 1, t, b);  
  38. }  
  39.   
  40. int Query(int i, int l, int r)  
  41. {  
  42.     //查找注意看好了下面的if条件,其实就是待查区间和已知总区间的四种关系:  
  43.     //完全相等,左相交,右相交,内含关系  
  44.         if (l == segTree[i].l&&r == segTree[i].r)  
  45.             return segTree[i].nSum;  
  46.     int mid = (segTree[i].l + segTree[i].r) >> 1;  
  47.     if (r <= mid)  
  48.         return Query(i << 1, l, r);  
  49.     else if (l>mid)  
  50.         return Query(i << 1 | 1, l, r);  
  51.     else  
  52.         return Query(i << 1, l, mid) + Query(i << 1 | 1, mid + 1, r);  
  53. }  
  54.   
  55. int main()  
  56. {  
  57.     int T;  
  58.     int iCase = 0;  
  59.     int n, i;  
  60.     char str[10];  
  61.     int a, b;  
  62.     scanf("%d", &T);  
  63.     while (T--)  
  64.     {  
  65.         iCase++;  
  66.         scanf("%d", &n);  
  67.         for (i = 1; i <= n; i++)  
  68.             scanf("%d", &num[i]);  
  69.         Build(1, 1, n);  
  70.         printf("Case %d:\n", iCase);  
  71.         while (scanf("%s", &str))  
  72.         {  
  73.             if (strcmp(str, "End") == 0)  
  74.                 break;  
  75.             scanf("%d%d", &a, &b);  
  76.             if (strcmp(str, "Add") == 0)  
  77.                 Add(1, a, b);  
  78.             else if (strcmp(str, "Sub") == 0)  
  79.                 Add(1, a, -b);//减少人数,所以是-b  
  80.             else  
  81.                 printf("%d\n", Query(1, a, b));  
  82.         }  
  83.     }  
  84.     return 0;  
  85. }  

阅读全文
0 0