链接:http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1237
Total Submissions: 429 (101 users) Accepted: 92 (76 users)
[ My Solution ]
话说当年swgr早上起床时经常在一堆颜色相近但款式不同的袜子堆里找到两只配对的袜子,为此常常要浪费不少时间。久而久之,swgr终于想到了一劳永逸的办法:他买了一大堆一模一样的袜子,这样就不用担心配对的问题了。
由于袜子太多,swgr把它们随便地分装进了N个抽屉里,每个抽屉都装着一些袜子。这样一来,就会出现有的抽屉里的袜子是刚好能凑成若干双的,有的抽屉里的袜子却会多出一只。
另外,swgr还会不定期补充袜子的数量。有时他想知道:从第i个抽屉到第j个抽屉的所有抽屉里,有多少个抽屉里的袜子是刚好能凑成若干双呢?
本题只有一组测试数据。输入数据的第一行为一个数N,表示有N个抽屉。
接下来一行有N个数,表示N个抽屉里初始时的袜子数。
接下来一行有一个数Q,表示一共有Q个操作。
接下来Q行,每行表示一个操作。操作有两类,一类操作是P a b,表示swgr买了b只袜子并放进了第a号抽屉中;另一类操作是C x y,表示swgr想知道现在从第x个抽屉到第y个抽屉的所有抽屉里(包括抽屉x和抽屉y),有多少个抽屉里的袜子刚好能凑成若干双。
数据范围:1≤N,Q≤100000,每个抽屉的初始袜子只数和每次买袜子的只数不超过20。抽屉编号为1号到N号。并保证1≤a≤N,1≤x≤y≤N。
对于每个C操作,输出一行,表示对应问题的答案,即满足题意的抽屉的个数。
10
5 4 9 1 3 8 9 5 2 17
4
C 1 2
P 1 1
C 1 2
C 3 4
1
2
0
思路:这道题目有两种写法,一种是线段树,一种是树状数组。下面的代码是树状数组。
代码:
68 #include <stdio.h> 69 int m,n; 70 int a[100004],b[100004]; 71 int lo(int x) 72 { 73 return x&(-x); 74 } 75 void update(int cou,int x)//树状数组的更新代码 76 { 77 while(cou<=n) 78 { 79 a[cou]+=x; 80 cou+=lo(cou); 81 } 82 } 83 int sum(int x)//树状数组的求前n项和代码 84 { 85 int s=0; 86 while(x>0) 87 { 88 s=s+a[x]; 89 x=x-lo(x); 90 } 91 return s; 92 } 93 int main() 94 { 95 int i,j; 96 char op[10]; 97 int xx; 98 int x1,x2,x3; 99 int s; 100 while(scanf("%d",&n)!=EOF) 101 { 102 for(i=0;i<=n;i++) 103 { 104 a[i]=0; 105 } 106 for(i=1;i<=n;i++) 107 { 108 scanf("%d",&b[i]); 109 if(b[i]%2==0)//如果能凑成双的袜子,就把这个抽屉置为1 110 update(i,1); 111 } 112 scanf("%d",&m); 113 while(m--) 114 { 115 scanf("%s",op); 116 if(op[0]=='P') 117 { 118 scanf("%d%d",&x1,&x2); 119 if(b[x1]%2==0&&(b[x1]+x2)%2==1)//如果之前能凑成双的袜子,现在加上放抽屉的却不能,就-1,即将该点置为0 120 update(x1,-1); 121 if(b[x1]%2==1&&(b[x1]+x2)%2==0)//如果之前不能凑成双的袜子,现在加上放抽屉的却能,就+1,即将该点置为1 122 update(x1,1); 123 b[x1]=b[x1]+x2; 124 } 125 if(op[0]=='C') 126 { 127 scanf("%d%d",&x1,&x2); 128 s=sum(x2)-sum(x1-1);//求x1到x2的和。 129 printf("%d\n",s); 130 } 131 } 132 } 133 return 0; 134 } //如果没看懂,建议仔细看看树状数组。