【线段树练习】 区间取模后统计%7
题目描述 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
//嗯。。本题是一道线段树的模板。
//可以“较容易”得知,一个数x在加上i后对7的取余也会加上(i mod 7)。
//则可以在建树时在每个节点坐标处设置一个数组num表示这段数对7取余为0、1、2、……6的个数
//在加数时进行余数位移,举个栗子:在一个结点数段中加2
//0 1 2 3 4 5 6 …… 对7的余数(i)
//2 3 4 5 3 6 7 ……对7的余数个数(num【i】)
//6 7 2 3 4 5 3 ……整体向右移(2 mod 7)位,类似于一个环。。
//详见代码
#include<bits/stdc++.h>
using namespace std;
struct point
{ int num[7];int die;};
int n,q,x,y,ai;
char o;
point f[405000]={};
inline void read(int &x)
{
x=0;int f=1;char s=getchar();
for(;s<'0'||s>'9';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=(x<<3)+(x<<1)+s-48;
x*=f;
}
inline void spa(int root,int ai)
{
int b[7]={};
for (int i=0;i<=6;i++)
b[(i+ai)%7]=f[root].num[i];
for (int i=0;i<=6;i++)
f[root].num[i]=b[i];
}
inline void pk(int root,int dead)
{
spa(root<<1,dead);
spa((root<<1)+1,dead);
f[root<<1].die+=dead;
f[(root<<1)+1].die+=dead;
f[root].die=0;
}
inline void dpk(int left,int right,int root)
{
if (x>right||x<left) return;
if (left==right) {f[root].num[y%7]++;return;}
int mid=(left+right)>>1;
dpk(left,mid,root<<1);dpk(mid+1,right,(root<<1)+1);
for (int i=0;i<=6;i++)
f[root].num[i]=f[root<<1].num[i]+f[(root<<1)+1].num[i];
}
inline void dfn(int left,int right,int root)
{
if (x>right||y<left) return;
if (x<=left&&y>=right)
{
f[root].die+=ai;
spa(root,ai);
return;
}
int mid=(left+right)>>1;
pk(root,f[root].die);
dfn(left,mid,root<<1);dfn(mid+1,right,(root<<1)+1);
for (int i=0;i<=6;i++)
f[root].num[i]=f[root<<1].num[i]+f[(root<<1)+1].num[i];
}
inline int search(int left,int right,int root)
{
if (x>right||y<left) return 0;
if (x<=left&&y>=right) return f[root].num[0];
int mid=(left+right)>>1;
pk(root,f[root].die);
return search(left,mid,root<<1)+search(mid+1,right,(root<<1)+1);
}
int main()
{
read(n);
for (int i=1;i<=n;i++)
{
read(y);
x=i;
dpk(1,n,1);
}
read(q);
for (int i=1;i<=q;i++)
{
o=getchar();
read(x);read(y);
if (o=='a') {read(ai);dfn(1,n,1);}
else printf("%d\n",search(1,n,1));
}
return 0;
}

浙公网安备 33010602011771号