中央情报局要研究敌人究竟演习什么战术,所以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: ",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 ",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 }
B - I Hate It
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
Input本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。
当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
Output对于每一次询问操作,在一行里面输出最高成绩。Sample Input
5 6 1 2 3 4 5 Q 1 5 U 3 6 Q 3 4 Q 4 5 U 2 9 Q 1 5
Sample Output
5 6 5 9
Hint
Huge input,the C function scanf() will work better than cin
这一道题就是pushup函数改变了,因为要求的是最大值,所以我们在子节点父节点中存的也应该是我们最终的目标
代码:
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=200005; 13 int sum[maxn<<2],add[maxn<<2]; 14 void pushup(int rt) 15 { 16 sum[rt]=max(sum[rt<<1],sum[rt<<1|1]); 17 } 18 void build(int l,int r,int rt) 19 { 20 if(l==r) 21 { 22 scanf("%d",&sum[rt]); 23 return; 24 } 25 int m=(l+r)>>1; 26 build(l,m,rt<<1); 27 build(m+1,r,rt<<1|1); 28 pushup(rt); 29 } 30 void update(int pos,int c,int l,int r,int rt) 31 { 32 if(l==r) 33 { 34 sum[rt]=c; 35 return; 36 } 37 int m=(l+r)>>1; 38 if(pos<=m) update(pos,c,l,m,rt<<1); 39 else update(pos,c,m+1,r,rt<<1|1); 40 pushup(rt); 41 } 42 int query(int L,int R,int l,int r,int rt) 43 { 44 if(L<=l && R>=r) 45 { 46 return sum[rt]; 47 } 48 int m=(l+r)>>1; 49 int ans=0; 50 if(L<=m) ans=max(ans,query(L,R,l,m,rt<<1)); 51 if(R>m) ans=max(ans,query(L,R,m+1,r,rt<<1|1)); 52 return ans; 53 } 54 int main() 55 { 56 int n,m; 57 char e[5]; 58 while(~scanf("%d%d",&n,&m)) 59 { 60 memset(sum,0,sizeof(sum)); 61 build(1,n,1); 62 while(m--) 63 { 64 int x,y; 65 scanf("%s",e); 66 scanf("%d%d",&x,&y); 67 if(e[0]=='Q') 68 { 69 printf("%d ",query(x,y,1,n,1)); 70 } 71 else if(e[0]=='U') 72 { 73 update(x,y,1,n,1); 74 } 75 } 76 } 77 return 0; 78 }
C - A Simple Problem with Integers
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.
Output
You need to answer all Q commands in order. One answer in a line.
Sample Input
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4
Sample Output
4 55 9 15
Hint
本题是区间修改和上面两个不一样,区间修改就要使用到标记,其次有些人用的是结构体里面存有这个节点区间的左右边界
而我使用的是再传参的时候把边界传给下一个节点,这两种方法都可以
上代码:
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=200005; 13 typedef long long ll; 14 ll sum[maxn<<2],add[maxn<<2]; 15 void pushup(ll rt) 16 { 17 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 18 } 19 void build(ll l,ll r,ll rt) 20 { 21 if(l==r) 22 { 23 scanf("%lld",&sum[rt]); 24 return; 25 } 26 ll m=(l+r)>>1; 27 build(l,m,rt<<1); 28 build(m+1,r,rt<<1|1); 29 pushup(rt); 30 } 31 void pushdown(ll rt,ll ln,ll rn) 32 { 33 if(add[rt]) 34 { 35 add[rt<<1]+=add[rt]; 36 add[rt<<1|1]+=add[rt]; 37 sum[rt<<1]+=add[rt]*ln; 38 sum[rt<<1|1]+=add[rt]*rn; 39 add[rt]=0; 40 } 41 } 42 void update(ll L,ll R,ll C,ll l,ll r,ll rt) 43 { 44 if(l>=L && r<=R) 45 { 46 sum[rt]+=(r-l+1)*C; //不要忘了这里是+= 47 add[rt]+=C; 48 return; 49 } 50 ll m=(l+r)>>1; 51 pushdown(rt,m-l+1,r-m); 52 if(L<=m) update(L,R,C,l,m,rt<<1); 53 if(R>m) update(L,R,C,m+1,r,rt<<1|1); 54 pushup(rt); 55 } 56 ll query(ll L,ll R,ll l,ll r,ll rt) 57 { 58 if(L<=l && R>=r) 59 { 60 return sum[rt]; 61 } 62 ll m=(l+r)>>1; 63 pushdown(rt,m-l+1,r-m); 64 ll ans=0; 65 if(L<=m) ans+=query(L,R,l,m,rt<<1); 66 if(R>m) ans+=query(L,R,m+1,r,rt<<1|1); 67 return ans; 68 } 69 int main() 70 { 71 ll n,m; 72 char e[5]; 73 scanf("%lld%lld",&n,&m); 74 build(1,n,1); 75 while(m--) 76 { 77 scanf("%s",e); 78 if(e[0]=='Q') 79 { 80 ll x,y; 81 scanf("%lld%lld",&x,&y); 82 printf("%lld ",query(x,y,1,n,1)); 83 } 84 else if(e[0]=='C') 85 { 86 ll x,y,z; 87 scanf("%lld%lld%lld",&x,&y,&z); 88 update(x,y,z,1,n,1); 89 } 90 } 91 return 0; 92 }