线段树练习4
2017-08-04 08:34
204 查看
线段树练习4
codevs题号: 4919
时间限制: 1 s
空间限制: 128000 KB
题目描述 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
100%:1< N<= 100000,1< Q<= 100000
题解:
比较水啊这题,我们可以在线段树的结构体数组中加上一个数组g[i]表示这个区间中与7取余为i的数有多少个。每次更新时都更新这个数组的值就好了,具体看代码。
codevs题号: 4919
时间限制: 1 s
空间限制: 128000 KB
题目描述 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
100%:1< N<= 100000,1< Q<= 100000
题解:
比较水啊这题,我们可以在线段树的结构体数组中加上一个数组g[i]表示这个区间中与7取余为i的数有多少个。每次更新时都更新这个数组的值就好了,具体看代码。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; long long int a[200010],add[800010]; int n,m,x,y,v,pd,num=0; struct hh { int f,l,r,ls,rs;//ls为左子节点,rs为右子节点 long long int date; int g[10];//g[i]保存 此区间中和7取余为i的数右多少个 }t[800010]; char pdd[10]; void build(int l,int r) { num++; int i=num; for(int j=0;j<7;j++) t[i].g[j]=0;//手动初始化 t[i].l=l;t[i].r=r; if(l!=r) { t[i].ls=num+1; build(l,(l+r)/2);//建立左子节点 t[i].rs=num+1; build(((l+r)/2+1),r);//建立右子节点 for(int j=0;j<7;j++)//父节点的g数组的值就是子节点的g数组的和 { t[i].g[j]=t[t[i].ls].g[j]+t[t[i].rs].g[j]; } } else if(l==r) { t[i].g[(a[l]%7)]=1;//叶子节点 直接赋值 } } void pushdown(int i)//更新子节点的值 { if(add[i]!=0) { int s[10],va=add[i];//利用一个s数组,保存更新后的值 for(int j=0;j<7;j++) { s[(j+va)%7]=t[t[i].ls].g[j];//左儿子更新数据 } for(int j=0;j<7;j++)//再把更新后数据赋给节点的g数组 t[t[i].ls].g[j]=s[j]; for(int j=0;j<7;j++) { s[(j+va)%7]=t[t[i].rs].g[j];//右儿子更新数据 } for(int j=0;j<7;j++)//把更新后数据赋给节点的g数组 t[t[i].rs].g[j]=s[j]; add[t[i].ls]+=va; add[t[i].rs]+=va; add[i]=0; } } void update(int i,int l,int r,int value) { if(t[i].l==l&&t[i].r==r)//完全覆盖,直接算 { add[i]+=value; int s[10]; for(int j=0;j<7;j++) { s[(j+value)%7]=t[i].g[j];//利用一个s数组,保存更新后的值 } for(int j=0;j<7;j++)//再把更新后数据赋给节点的g数组 t[i].g[j]=s[j]; return ; } if(t[i].l==t[i].r) return ; pushdown(i);//把延迟更新的值传给子节点 int z=(t[i].l+t[i].r)/2;//区间更新的套路啦 if(r<=z) update(t[i].ls,l,r,value); else if(l>z) update(t[i].rs,l,r,value); else { update(t[i].ls,l,z,value); update(t[i].rs,z+1,r,value); } for(int j=0;j<7;j++)//父节点的g数组的值就是子节点的g数组的和 { t[i].g[j]=t[t[i].ls].g[j]+t[t[i].rs].g[j]; } } long long int query(int i,int l,int r)//求和 { if(t[i].l==l&&t[i].r==r)//完全覆盖,直接返回值 { return t[i].g[0]; } pushdown(i);//降延迟更新的值传给儿子节点 int z=(t[i].l+t[i].r)/2;//还是线段树区间更新的套路 if(r<=z) return query(t[i].ls,l,r); else if(l>z) return query(t[i].rs,l,r); else return query(t[i].ls,l,z)+query(t[i].rs,z+1,r); } int main() { memset(add,0,sizeof(add)); cin>>n; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); a[i]%=7; //预处理先 mod7 } build(1,n); cin>>m; for(int i=1;i<=m;i++) { scanf("%s",pdd); { if(pdd[0]=='a') { scanf("%d%d%d",&x,&y,&v); if((v%=7)!=0)//要加上的值如果和mod7为0的话就没什么用了,不必更新。 update(1,x,y,v%7); } else if(pdd[0]=='c') { scanf("%d%d",&x,&y); cout<<query(1,x,y)<<endl; } } } return 0; }
相关文章推荐
- 1082 线段树练习 3
- codevs 4927 线段树练习5
- 2016夏季练习——线段树
- hdu1394--Minimum Inversion Number(线段树求逆序数,纯为练习)
- 1081 线段树练习 2 codevs
- 小白初识线段树(线段树原理+专题练习)
- 【codevs 1080】线段树练习 之 花样解法
- 【codevs 1081】线段树练习 2
- 线段树练习1
- 【线段树】Codevs线段树练习1.2.3及线段树学习笔记
- CodeVS4919 线段树练习4
- 杭电 线段树 (个人整理(基础入门版))(多题练习.)(简单风格)
- COdeVS——T 1082 线段树练习 3 (分块练习)
- 线段树练习 1,2
- [CodeVS1082] 线段树练习3(区间修改+询问区间和)
- [Codevs] 1080 线段树练习
- codevs 4927 线段树练习5
- [线段树练习2] 影子的宽度 - 统计标记个数
- 线段树练习2
- codevs 1082 线段树练习3