4919 线段树练习4
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
题目描述 Description
给你N个数,有两种操作
1:给区间[a,b]内的所有数都增加X
2:询问区间[a,b]能被7整除的个数
输入描述 Input Description
第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数。如果第一个数是add,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果是count,表示统计区间[a,b]能被7整除的个数
输出描述 Output Description
对于每个询问输出一行一个答案
样例输入 Sample Input
3 2 3 4 6 count 1 3 count 1 2 add 1 3 2 count 1 3 add 1 3 3 count 1 3
样例输出 Sample Output
0
0
0
1
数据范围及提示 Data Size & Hint
10%:1<N<=10,1<Q<=10
30%:1<N<=10000,1<Q<=10000
100%:1<N<=100000,1<Q<=100000
分析 Analysis
分块!
相比线段树分块真的写起来很方便啊qwq
每个块保存块内关于 7 的剩余系的元素数量
(就是%7以后 0~6 的数量啦)
关键是add 操作,真恶心
用以前线段树的那套修改方案,最多过3个点
看了看TJM的方案:
每次整块增值时拉低bdd(负责保存历经修改以后整除 7 的数字到底是哪一个)
查询时计数 mod[ block[ i ] ][ bdd[ i ] ]
代码 Code
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #define maxn 1000000 5 using namespace std; 6 7 char str[maxn/100]; 8 int block[maxn],mod[maxn][10],size,arr[maxn],add[maxn],bdd[maxn],n,m; 9 10 void modify(){ 11 int a,b,c; 12 scanf("%d%d%d",&a,&b,&c); 13 a--,b--,c %= 7; 14 if(!c) return; 15 16 if(block[a] == block[b]){ 17 for(int i = a;i <= b;i++){ 18 mod[block[i]][arr[i]]--; 19 arr[i] = (arr[i]+c)%7; 20 mod[block[i]][arr[i]]++; 21 } 22 }else{ 23 24 for(int i = a;i <= block[a]*size-1;i++) 25 mod[block[i]][arr[i]]--, 26 arr[i] = (arr[i]+c)%7, 27 mod[block[i]][arr[i]]++; 28 for(int i = (block[b]-1)*size;i <= b;i++) 29 mod[block[i]][arr[i]]--, 30 arr[i] = (arr[i]+c)%7, 31 mod[block[i]][arr[i]]++; 32 for(int i = block[a]+1;i < block[b];i++) 33 add[i] = (add[i]+c)%7, 34 bdd[i] = (bdd[i]-c+7)%7; 35 36 } 37 } 38 39 void count(){ 40 int a,b; 41 scanf("%d%d",&a,&b); 42 a--,b--; 43 int ans = 0; 44 45 if(block[a] == block[b]){ 46 for(int i = a;i <= b;i++) 47 ans += ((arr[i]+add[block[i]])%7)?0:1; 48 }else{ 49 50 for(int i = a;i <= block[a]*size-1;i++) 51 ans += ((arr[i]+add[block[i]])%7)?0:1; 52 for(int i = (block[b]-1)*size;i <= b;i++) 53 ans += ((arr[i]+add[block[i]])%7)?0:1; 54 for(int i = block[a]+1;i < block[b];i++) 55 ans += mod[i][bdd[i]]; 56 57 } 58 59 printf("%d ",ans); 60 } 61 62 void show(){ 63 for(int i = 0;i < n;i++){ 64 printf("%d ",arr[i]+add[block[i]]); 65 }cout << endl; 66 } 67 68 int main(){ 69 scanf("%d",&n); 70 size = (int)sqrt(n)+1; 71 for(int i = 0;i < n;i++) block[i] = i/size+1; 72 // for(int i = 0;i < n;i++) printf("#%d: block %d ",i,block[i]); 73 for(int i = 0;i < n;i++){ 74 scanf("%d",&arr[i]); 75 arr[i] %= 7; 76 mod[block[i]][arr[i]]++; 77 } 78 // show(); 79 scanf("%d",&m); 80 for(int i = 0;i < m;i++){ 81 scanf("%s",str); 82 if(str[0] == 'a') modify(); 83 else count(); 84 // show(); 85 } 86 87 return 0; 88 }