[关闭]
@wwwqeqeqeqe 2017-03-27T19:54:33.000000Z 字数 2451 阅读 820

寒假训练专题二(线段树)


A

题目大意

先输入一个数T,表示有T组数据。在每组数据中,第一行给出一个数N,表示有N个工兵营地。接着输入N个数,表示第i个工兵营地里有ai个人,然后输入命令,命令的种类一共有四种,分别表示增加,减少人数,查询一个范围内工兵营地的总人数,以及一个结束语句。让你输出每个查询语句中工兵营地的总人数。

解题思路

裸的线段树模板,减少人数可以表示为增加负数的人数。

AC代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<cmath>
  6. using namespace std;
  7. const int maxn=1e5+5;
  8. struct node
  9. {
  10. int l,r,val;
  11. };
  12. int T,N,a[maxn];
  13. char s[15];
  14. node tree[maxn*4];
  15. void pushup(int x)
  16. {
  17. tree[x].val=tree[x<<1].val+tree[x<<1|1].val;
  18. }
  19. void build(int l,int r,int x,int a[])
  20. {
  21. tree[x].l=l;
  22. tree[x].r=r;
  23. if(l==r)
  24. tree[x].val=a[l];
  25. else
  26. {
  27. int mid=(l+r)>>1;
  28. build(l,mid,x<<1,a);
  29. build(mid+1,r,x<<1|1,a);
  30. pushup(x);
  31. }
  32. }
  33. void add(int pos,int v,int x)
  34. {
  35. if(tree[x].l==tree[x].r)
  36. tree[x].val+=v;
  37. else
  38. {
  39. int mid=(tree[x].l+tree[x].r)>>1;
  40. if(pos<=mid)
  41. add(pos,v,x<<1);
  42. else
  43. add(pos,v,x<<1|1);
  44. pushup(x);
  45. }
  46. }
  47. int Query(int l,int r,int x)
  48. {
  49. if(tree[x].l>=l&&tree[x].r<=r)
  50. return tree[x].val;
  51. int ans=0;
  52. int mid=(tree[x].l+tree[x].r)>>1;
  53. if(l<=mid)
  54. ans+=Query(l,r,x<<1);
  55. if(mid<r)
  56. ans+=Query(l,r,x<<1|1);
  57. return ans;
  58. }
  59. int main()
  60. {
  61. int z,y;
  62. scanf("%d",&T);
  63. int casee=0;
  64. while(T--)
  65. {
  66. memset(tree,0,sizeof(tree));
  67. memset(a,0,sizeof(a));
  68. scanf("%d",&N);
  69. for(int i=1;i<=N;i++)
  70. scanf("%d",&a[i]);
  71. build(1,N,1,a);
  72. printf("Case %d:\n",++casee);
  73. while(~scanf("%s",s))
  74. {
  75. if(s[0]=='E')
  76. break;
  77. else if(s[0]=='Q')
  78. {
  79. scanf("%d%d",&z,&y);
  80. printf("%d\n",Query(z,y,1));
  81. }
  82. else if(s[0]=='A')
  83. {
  84. scanf("%d%d",&z,&y);
  85. add(z,y,1);
  86. }
  87. else if(s[0]=='S')
  88. {
  89. scanf("%d%d",&z,&y);
  90. add(z,-y,1);
  91. }
  92. }
  93. }
  94. return 0;
  95. }

B

题目大意

先给你N个数,表示气球的总数,在接下来的若干行中,输入两个数a和b,表示从第a个气球到第b个气球每个气球上了一次颜色,最后输出每个气球一共被上了几次颜色。

解题思路

可以通过线段树解决这个问题。在进行上色的过程中,通过判断左右边界是否相等来进行数据增加记录,在mid左边就查找x*2,右边的就查找x*2+1,最后查找的过程同样如此,最后找到每个气球被上色的数量。

AC代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<cmath>
  6. using namespace std;
  7. const int maxn=1e5+5;
  8. struct node
  9. {
  10. int l,r,val;
  11. };
  12. node tree[maxn*4];
  13. int N,t;
  14. void build(int l,int r,int x)
  15. {
  16. tree[x].l=l;
  17. tree[x].r=r;
  18. tree[x].val=0;
  19. if(l!=r)
  20. {
  21. int mid=(l+r)>>1;
  22. build(l,mid,x<<1);
  23. build(mid+1,r,x<<1|1);
  24. }
  25. }
  26. void add(int l,int r,int x)
  27. {
  28. if(tree[x].l==l&&tree[x].r==r)
  29. tree[x].val++;
  30. else
  31. {
  32. int mid=(tree[x].l+tree[x].r)>>1;
  33. if(l<=mid&&r>mid)
  34. {
  35. add(l,mid,x<<1);
  36. add(mid+1,r,x<<1|1);
  37. }
  38. else
  39. {
  40. if(r<=mid)
  41. add(l,r,x<<1);
  42. else
  43. add(l,r,x<<1|1);
  44. }
  45. }
  46. }
  47. int Query(int pos,int x)
  48. {
  49. t+=tree[x].val;
  50. if(tree[x].l!=tree[x].r)
  51. {
  52. int mid=tree[x].l+tree[x].r>>1;
  53. if(pos<=mid)
  54. Query(pos,x<<1);
  55. else
  56. Query(pos,x<<1|1);
  57. }
  58. return t;
  59. }
  60. int main()
  61. {
  62. int a,b;
  63. while(~scanf("%d",&N)&&N)
  64. {
  65. memset(tree,0,sizeof(tree));
  66. build(1,N,1);
  67. for(int i=0; i<N; i++)
  68. {
  69. scanf("%d%d",&a,&b);
  70. add(a,b,1);
  71. }
  72. for(int i=1;i<N;i++)
  73. {
  74. t=0;
  75. printf("%d ",Query(i,1));
  76. }
  77. t=0;
  78. printf("%d\n",Query(N,1));
  79. }
  80. return 0;
  81. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注