【题目】
题目描述:
给定长度均为 n n n 的数列 a , b a,b a,b,其中 b b b 数列为 [ 1 1 1 , n n n ] 的全排列, a a a 数列全为 0 0 0。
你需要支持 q q q 次操作,操作分为 a d d add add 和 q u e r y query query 两种。
- a d d add add l l l r r r 表示 a l , a l + 1 , . . . , a r − 1 , a r a_l,a_{l+1},...,a_{r−1},a_r al,al+1,...,ar−1,ar 均加 1 1 1。
- q u e r y query query l l l r r r 表示求 ∑ i = l r ⌊ a i b i ⌋ \sum_{i=l}^{r}\lfloor \frac{a_i}{b_i}\rfloor ∑i=lr⌊biai⌋。
其中 ⌊ x ⌋ ⌊x⌋ ⌊x⌋ 表示对 x x x 向下取整。
输入格式:
第一行有两个整数 n , q n,q n,q, n n n 表示 a , b a,b a,b 数列长度, q q q 表示操作次数
接下来一行 n n n 个整数,表示 b b b 数列
接下来 q q q 行,每行表示 a d d add add 或 q u e r y query query 操作
输出格式:
对于每一个 q u e r y query query 操作,输出一行整数表示对应的答案
样例数据:
输入
5 12
1 5 2 4 3
add 1 4
query 1 4
add 2 5
query 2 5
add 3 5
query 1 5
add 2 4
query 1 4
add 2 5
query 2 5
add 2 2
query 1 5
输出
1
1
2
4
4
6
提示:
对于
100
%
100\%
100% 的数据,
n
,
q
≤
100000
n,q≤100000
n,q≤100000,
1
≤
l
,
r
≤
n
1≤l,r≤n
1≤l,r≤n。
保证
b
b
b 数列是 [
1
1
1 ,
n
n
n ] 的全排列
【分析】
我们用线段树来做这道题,对于每个区间都维护一下 b i − a i % b i b_i-a_i\%b_i bi−ai%bi 的最小值(设为 n u m num num)
其实 n u m num num 也可以粗略地理解成第 i i i 位还要加上 n u m i num_i numi 个数才能使答案再增加 1 1 1
然后分以下两种情况来统计:
- n u m > 1 num>1 num>1,那么这时区间加 1 1 1 不会对答案有贡献,直接 n u m − 1 num-1 num−1 即可
- 否则,就递归到 n u m = 1 num=1 num=1 的点,此时它肯定对答案有 1 1 1 的贡献,加上后更新 n u m = b i num=b_i num=bi 即可
由于统计答案时没有修改操作,所以我们可以直接用树状数组统计答案
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define lowbit(x) x&-x
using namespace std;
char s[10];
int n,q,num[N],bit[N];
int Min[N<<2],add[N<<2];
void Build(int root,int l,int r)
{
if(l==r)
{
Min[root]=num[l];
return;
}
int mid=(l+r)>>1;
Build(root<<1,l,mid);
Build(root<<1|1,mid+1,r);
Min[root]=min(Min[root<<1],Min[root<<1|1]);
}
void Pushdown(int root)
{
add[root<<1]+=add[root];
Min[root<<1]-=add[root];
add[root<<1|1]+=add[root];
Min[root<<1|1]-=add[root];
add[root]=0;
}
void Add(int i)
{
while(i<=n)
{
bit[i]++;
i+=lowbit(i);
}
}
void Modify(int root,int l,int r,int x,int y)
{
if(l==r&&Min[root]==1) {Min[root]=num[l];Add(l);return;}
if(l>=x&&r<=y&&Min[root]>1) {add[root]++;Min[root]--;return;}
int mid=(l+r)>>1;
if(add[root]) Pushdown(root);
if(x<=mid) Modify(root<<1,l,mid,x,y);
if(y>mid) Modify(root<<1|1,mid+1,r,x,y);
Min[root]=min(Min[root<<1],Min[root<<1|1]);
}
int Query(int i)
{
int ans=0;
while(i)
{
ans+=bit[i];
i-=lowbit(i);
}
return ans;
}
int main()
{
freopen("eta.in","r",stdin);
freopen("eta.out","w",stdout);
int l,r,i;
scanf("%d%d",&n,&q);
for(i=1;i<=n;++i)
scanf("%d",&num[i]);
Build(1,1,n);
for(i=1;i<=q;++i)
{
scanf("%s%d%d",s,&l,&r);
if(s[0]=='a') Modify(1,1,n,l,r);
else printf("%d\n",Query(r)-Query(l-1));
}
fclose(stdin);
fclose(stdout);
return 0;
}