A - 敌兵布阵(线段树)

C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。
中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:"你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书,现在尝到苦果了吧!”Tidy说:"我知错了。。。"但Windbreaker已经挂掉电话了。Tidy很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?不过如果你的程序效率不够高的话,Tidy还是会受到Derek的责骂的.

Input第一行一个整数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条命令
Output对第i组数据,首先输出“Case i:”和回车,
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。
Sample Input

1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End 

Sample Output

Case 1:
6
33
59

注意:

1、在查询query函数中,里面两个判断条件之间没有关系,不要使用“else”来使他们联系在一起

2、注意在点修改中只要查到了那个修改的点,修改完要加上“return”

点修改用else,区间修改和区间查询不用else

错的我绝望。。。。。。

上代码:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<stack>
  7 #include<vector>
  8 using namespace std;
  9 #define lson l,m,rt<<1
 10 #define rson m+1,r,rt<<1|1
 11 const int INF=0x3f3f3f3f;
 12 const int maxn=50005;
 13 int sum[maxn<<2],add[maxn<<2];
 14 int v[maxn],n;
 15 void pushup(int root) //统计每个点下一级左右分支的和
 16 {
 17     sum[root]=sum[root<<1]+sum[root<<1|1];
 18 }
 19 void build(int l,int r,int root)
 20 {
 21     if(l==r)  //当l==r的是侯就代表树到达了底部,此时既可以对他赋值,其中l,r是
 22     {
 23         //代表这个位置存的值对应的区间
 24         scanf("%d",&sum[root]);
 25         return;
 26     }
 27     int mid=(l+r)>>1;
 28     build(l,mid,root<<1);
 29     build(mid+1,r,root<<1|1);
 30     pushup(root);
 31 }
 32 //点修改
 33 void update(int l,int p,int ll,int rr,int root)//这个l代表要修改的值
 34 {
 35     if(ll==rr)
 36     {
 37         sum[root]+=p;
 38         return; //这里没有加return
 39     }
 40     int mid=(ll+rr)>>1;
 41     //这里要判断一下,保证你递归的区间中包含这个要修改的点
 42     if(l<=mid) update(l,p,ll,mid,root<<1); //注意这里是<=,等于号
 43     else update(l,p,mid+1,rr,root<<1|1);
 44     pushup(root);//更新完子节点之后不要忘记更新父节点
 45 }
 46 //下推标记
 47 void pushdown(int root,int ln,int rn) //ln、rn为左右子树上数字的数量
 48 {
 49     if(add[root])
 50     {
 51         add[root<<1]+=add[root];
 52         add[root<<1|1]+=add[root];
 53         sum[root<<1]+=add[root]*ln;
 54         sum[root<<1|1]+=add[root]*rn;
 55         //消除父节点标记
 56         add[root]=0;
 57     }
 58 }
 59 //更新区间,本题不涉及
 60 void Update(int l,int r,int p,int ll,int rr,int root)
 61 {
 62     if(l<=ll && r<=rr) //满足这个条件就说明这个区间都在我们要修改的区间中
 63     {
 64         sum[root]+=(rr-ll+1)*p;
 65         add[root]+=p; //标记父节点,不能只更新父节点不更新子节点,要记录下来,一旦有机会就要更新
 66         return;
 67     }
 68     int mid=(ll+rr)>>1;
 69     pushdown(root,mid-ll+1,rr-mid);
 70     //这里要判断要递归的区间必须要和我们要修改的区间有交集
 71     if(l<=mid) Update(l,r,p,ll,mid,root<<1);
 72     if(rr>mid) Update(l,r,p,mid+1,rr,root<<1|1);
 73     pushup(root);
 74 }
 75 int query(int L,int R,int l,int r,int rt)
 76 {
 77 //    if(L<=l && R>=r)
 78 //    {
 79 //        return sum[rt];
 80 //    }
 81     if(L <= l && r <= R){
 82 
 83         return sum[rt];
 84 
 85     }
 86     int m=(l+r)>>1;
 87     //在查询之前要往下推标记,要不然可以有些区间没有及时更新
 88     //pushdown(rt,mid-l+1,r-mid);
 89     int ans=0;
 90 //    if(L<=m) ans+=query(L,R,lson);
 91 //    else if(R>m) ans+=query(L,R,rson);
 92 //    return ans;
 93     if(L <= m)
 94 
 95         ans += query(L,R,lson);
 96 
 97     if(R > m)   //上一个条件和下一个条件没有关系,所以这里不能用else
 98                 //找了半天<_>..............................................
 99         ans += query(L,R,rson);
100 
101     return ans;
102 }
103 int main()
104 {
105     int t,k=0,n;
106     char e[15];
107     char q[5][15]={
108         "Query",
109         "Add",
110         "Sub",
111         "End",
112     };
113     scanf("%d",&t);
114     while(t--)
115     {
116         memset(sum,0,sizeof(sum));
117         memset(add,0,sizeof(add));
118         memset(v,0,sizeof(v));
119         k++;
120         printf("Case %d:\n",k);
121         scanf("%d",&n);
122         build(1,n,1);
123         while(1)
124         {
125             scanf("%s",e);
126             if(strcmp(e,q[0])==0)
127             {
128                 int l,r;
129                 scanf("%d%d",&l,&r);
130                 int sum=query(l,r,1,n,1);  //这里的查询写错了
131                 printf("%d\n",sum);  //要查询的区间要写在前面,在那里查询写在后面T_T
132             }
133             else if(strcmp(e,q[1])==0)
134             {
135                 int l,r;
136                 scanf("%d%d",&l,&r);
137                 update(l,r,1,n,1);
138             }
139             else if(strcmp(e,q[2])==0)
140             {
141                 int l,r;
142                 scanf("%d%d",&l,&r);
143                 update(l,-r,1,n,1);
144             }
145             else if(strcmp(e,q[3])==0)
146             {
147                 break;
148             }
149         }
150     }
151     return 0;
152 }
View Code

猜你喜欢

转载自www.cnblogs.com/kongbursi-2292702937/p/10811118.html