前方预警:
题目:http://codevs.cn/problem/4919/
这一题比起其前面难度应该是提升了不少,因为对于一段区间的一部分改变后我们无法确定被7整除的个数,而且在区间加中被7整除的个数也难以更新。
关于这样的题我们要学会转化,已知题目要求求被7整除的数,而被7整除的数每7次便会出现一次,那么我们就取一下%,存在数组中就可以了。对于一段区间被七整除的个数,在指针中有很好的处理方法,代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
ll n,q,a,b,c,cnt = 0;
string s;
struct zt
{
ll l,r,cnt[7],sz,jia;
zt *lift,*right,*fa;
};
zt tree[MAXN];
void build(zt *root,ll l,ll r,zt *fa)
{
root->l = l;root->r = r;root->sz = (r - l + 1);root->jia = 0;root->fa = fa;
root->cnt[0] = root->sz;root->cnt[1] = 0;root->cnt[2] = 0;root->cnt[3] = 0;
root->cnt[4] = 0;root->cnt[5] = 0;root->cnt[6] = 0;
if(l == r)
return;
root->lift = &tree[++cnt];
root->right = &tree[++cnt];
ll mid = (l + r)>>1;
build(root->right,mid + 1,r,root);
build(root->lift,l,mid,root);
}
void add(zt *root,ll l,ll r,ll ql,ll qr,ll x)
{
ll ji[7];
if(root->jia&&l != r)
{
ll ji[7],ji2[7];
for(ll i = 0;i < 7;i ++)
{
ji[(i + root->jia)%7] = root->lift->cnt[i];
ji2[(i + root->jia)%7] = root->right->cnt[i];
}
for(int i = 0;i < 7;i ++)
{
root->lift->cnt[i] = ji[i];
root->right->cnt[i] = ji2[i];
}
root->lift->jia += root->jia;
root->right->jia += root->jia;
root->jia = 0;
}
if(l >= ql&&qr >= r)
{
for(int i = 0;i < 7;i ++)
ji[(i + x)%7] = root->cnt[i];
zt *j = root->fa;
while(j != NULL)
{
for(int i = 0;i < 7;i ++)
{
j->cnt[i] -= root->cnt[i];
j->cnt[i] += ji[i];
}
j = j->fa;
}
for(int i = 0;i < 7;i ++)
root->cnt[i] = ji[i];
root->jia += x;
return;
}
ll mid = (l + r)>>1;
if(ql <= mid)
add(root->lift,l,mid,ql,qr,x);
if(qr > mid)
add(root->right,mid + 1,r,ql,qr,x);
}
ll find(zt *root,ll l,ll r,ll ql,ll qr)
{
if(l >= ql&&qr >= r)
return root->cnt[0];
if(root->jia)
{
ll ji[7],ji2[7];
for(ll i = 0;i < 7;i ++)
{
ji[(i + root->jia)%7] = root->lift->cnt[i];
ji2[(i + root->jia)%7] = root->right->cnt[i];
}
for(int i = 0;i < 7;i ++)
{
root->lift->cnt[i] = ji[i];
root->right->cnt[i] = ji2[i];
}
root->lift->jia += root->jia;
root->right->jia += root->jia;
root->jia = 0;
}
ll mid = (l + r)>>1;
if(ql > mid)
return find(root->right,mid + 1,r,ql,qr);
if(qr <= mid)
return find(root->lift,l,mid,ql,qr);
return (find(root->right,mid + 1,r,ql,qr) + find(root->lift,l,mid,ql,qr));
}
int main()
{
scanf("%lld",&n);
build(tree,1,n,NULL);
for(int i = 1;i <= n;i ++)
{
scanf("%lld",&a);
add(tree,1,n,i,i,a);
}
scanf("%lld",&q);
for(int i = 1;i <= q;i ++)
{
cin>>s;
if(s == "add")
{
scanf("%lld %lld %lld",&a,&b,&c);
add(tree,1,n,a,b,c);
}
else
{
scanf("%lld %lld",&a,&b);
cout<<find(tree,1,n,a,b)<<'\n';
}
}
}