【线段树练习】 区间取模后统计%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;
}

 

 
posted @ 2018-05-15 15:29  风际神鸣  阅读(248)  评论(0)    收藏  举报