http://acm.hdu.edu.cn/showproblem.php?pid=6315
Problem Description
In a galaxy far, far away, there are two integer sequence a and b of length n.
b is a static permutation of 1 to n. Initially a is filled with zeroes.
There are two kind of operations:
- add l r: add one for al,al+1…ar
- query l r: query ∑ri=l⌊ai/bi⌋
题意:设计一个数据结构,支持两种操作:
1.[L,R]每个数+1
2.[L,R]每个数除以b[i]向下取整之和
思路:看到这个题想到是线段树,但是查询的这个东西很奇怪,难以维护。
后来读了大佬的这篇blog:https://blog.csdn.net/weixin_39453270/article/details/81211237
因为对于i位置,+b[i]次后,下取整比原来多1,因此如果一个区间+1后没有一个元素达到[除b[i]下取整+1]的地步,我们就可以打一个标记,这样就可以保证线段树的复杂度。
方便实现,我们逆向处理,变加为减,到达b[i]变成到达0。
#include <bits/stdc++.h>
using namespace std;
#define maxn (100000+100)
int n,m,b[maxn];
int ql,qr,_sum;
char cmd[10];
struct SegmentTree{
int subv[maxn*4],minv[maxn*4],sumv[maxn*4];
void clear()
{
memset(subv,0,sizeof(subv));
memset(minv,0,sizeof(minv));
memset(sumv,0,sizeof(sumv));
}
void build(int o,int l,int r)
{
if(l==r)minv[o]=b[l];
else
{
int mid=(l+r)/2;
build(o*2,l,mid);
build(o*2+1,mid+1,r);
minv[o]=min(minv[o*2],minv[o*2+1]);
}
}
void maintain(int o,int l,int r)
{
if(l<r)
{
sumv[o]=sumv[o*2]+sumv[o*2+1];
minv[o]=min(minv[o*2],minv[o*2+1])-subv[o];
}
else
{
minv[o]=b[l]-subv[o];
}
}
void pushdown(int o)
{
subv[o*2]+=subv[o];
subv[o*2+1]+=subv[o];
subv[o]=0;
}
void update(int o,int l,int r)
{
if(ql<=l&&qr>=r && minv[o]>1)
{
subv[o]++;
maintain(o,l,r);
}
else if(l==r)
{
minv[o]=b[l];
sumv[o]++;
subv[o]=0;
}
else
{
int mid=(l+r)/2;
pushdown(o);
maintain(o*2,l,mid);
maintain(o*2+1,mid+1,r);
if(ql<=mid)update(o*2,l,mid);
if(qr>mid)update(o*2+1,mid+1,r);
maintain(o,l,r);
}
}
void query(int o,int l,int r)
{
if(ql<=l&&qr>=r)_sum+=sumv[o];
else
{
int mid=(l+r)/2;
if(ql<=mid)query(o*2,l,mid);
if(qr>mid)query(o*2+1,mid+1,r);
}
}
}tree;
int main()
{
//freopen("input.in","r",stdin);
while(cin>>n>>m)
{
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
tree.clear();
tree.build(1,1,n);
while(m--)
{
scanf("%s%d%d",cmd,&ql,&qr);
if(cmd[0]=='a')tree.update(1,1,n);
else
{
_sum=0;
tree.query(1,1,n);
printf("%d\n",_sum);
}
}
}
return 0;
}