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的责骂的.
中央情报局要研究敌人究竟演习什么战术,所以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 }