[Codevs] 4919 线段树练习4
2017-09-14 16:11
260 查看
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 Input3 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 & Hint10%: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
#include<cstdio> #include<iostream> #include<cmath> #define maxn 1000000 using namespace std; char str[maxn/100]; int block[maxn],mod[maxn][10],size,arr[maxn],add[maxn],bdd[maxn],n,m; void modify(){ int a,b,c; scanf("%d%d%d",&a,&b,&c); a--,b--,c %= 7; if(!c) return; if(block[a] == block[b]){ for(int i = a;i <= b;i++){ mod[block[i]][arr[i]]--; arr[i] = (arr[i]+c)%7; mod[block[i]][arr[i]]++; } }else{ for(int i = a;i <= block[a]*size-1;i++) mod[block[i]][arr[i]]--, arr[i] = (arr[i]+c)%7, mod[block[i]][arr[i]]++; for(int i = (block[b]-1)*size;i <= b;i++) mod[block[i]][arr[i]]--, arr[i] = (arr[i]+c)%7, mod[block[i]][arr[i]]++; for(int i = block[a]+1;i < block[b];i++) add[i] = (add[i]+c)%7, bdd[i] = (bdd[i]-c+7)%7; } } void count(){ int a,b; scanf("%d%d",&a,&b); a--,b--; int ans = 0; if(block[a] == block[b]){ for(int i = a;i <= b;i++) ans += ((arr[i]+add[block[i]])%7)?0:1; }else{ for(int i = a;i <= block[a]*size-1;i++) ans += ((arr[i]+add[block[i]])%7)?0:1; for(int i = (block[b]-1)*size;i <= b;i++) ans += ((arr[i]+add[block[i]])%7)?0:1; for(int i = block[a]+1;i < block[b];i++) ans += mod[i][bdd[i]]; } printf("%d\n",ans); } void show(){ for(int i = 0;i < n;i++){ printf("%d ",arr[i]+add[block[i]]); }cout << endl; } int main(){ scanf("%d",&n); size = (int)sqrt(n)+1; for(int i = 0;i < n;i++) block[i] = i/size+1; // for(int i = 0;i < n;i++) printf("#%d: block %d\n",i,block[i]); for(int i = 0;i < n;i++){ scanf("%d",&arr[i]); arr[i] %= 7; mod[block[i]][arr[i]]++; } // show(); scanf("%d",&m); for(int i = 0;i < m;i++){ scanf("%s",str); if(str[0] == 'a') modify(); else count(); // show(); } return 0; }我不想退役qwq
相关文章推荐
- Codevs-4919 线段树练习4(区间加上一个值并求摸个区间整除k的数的个数,线段树+数组维护)
- [codevs4919] 线段树练习4
- codevs4919 线段树练习4
- CodeVs——T 4919 线段树练习4
- [CodeVS4919]线段树练习4
- codevs 4919 线段树练习4
- CodeVS4919 线段树练习4
- AC日记——线段树练习4 codevs 4919
- codevs1080线段树练习(树状数组)
- codevs 1082 线段树练习 3
- COdeVS——T 1082 线段树练习 3 (分块练习)
- Codevs1082 线段树练习 3 Lazy
- 【codevs3304】水果姐逛水果街Ⅰ 线段树练习
- Code Vs 1082 线段树练习 3
- 水题笔记:codevs 1080 线段树练习 [重口味线段树初次(单点修改)]
- <线段树系列4> codevs 4927 线段树练习5
- codevs1080线段树练习(zkw线段树)
- [Codevs] 1081 线段树练习 2 ----“分块!”
- Codevs 1080 线段树练习(CDQ分治)
- 【codevs1082】线段树练习 3