[Codevs] 4919 线段树练习4

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\n",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\n",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 }
我不想退役qwq

 

posted @ 2017-09-14 16:11  Leviaton  阅读(161)  评论(0编辑  收藏  举报