题意:给你一个长度为n的b[]数组和长度为n的a[]数组,b[]是1到n的全排列,a[]初始全为0,有两种操作:①add l r:a[]数组从l到r全部+1,②query l r:查询∑a[i]/b[i](l≤i≤r,向下取整)
- 因为b[]是n的一个全排列,并且对于所有的a[i]/b[i]很显然只会变化n/b[i]次,所以总共只会有n/1+n/2+…+n/3≈nlogn次变化
- 可以直接暴力每个位置上的每次变化(从0到n/b[i])会在第几次add操作之后
- 可以用二分,如果第k次add操作不会影响当前位置,那么这次操作就相当于0,否则相当于1,这里用前缀和处理,不过是要带修改的,所以可能要用树状数组,看前缀的1的数量s是否满足条件即可
- 总复杂度O(nlog²n)(好像还会多一个log,不过到不了极端情况)
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
typedef struct
{
int l, r;
int id, t;
}Que;
Que s[100005];
int len, b[100005], tre[100005];
char str[8];
vector<int> L[100005], R[100005], A[100005];
void Update(int k, int x)
{
while(k<=len)
{
tre[k] += x;
k += k&-k;
}
}
int Query(int k)
{
int ans = 0;
while(k)
{
ans += tre[k];
k -= k&-k;
}
return ans;
}
int main(void)
{
int n, i, j, l, r, m, last, mid, ans;
while(scanf("%d%d", &n, &m)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d", &b[i]);
len = m;
for(i=1;i<=m;i++)
{
scanf("%s%d%d", str+1, &s[i].l, &s[i].r);
s[i].id = i;
if(str[4]==0)
{
s[i].t = 1;
L[s[i].l].push_back(s[i].id);
R[s[i].r+1].push_back(s[i].id);
}
else
s[i].t = 0;
}
for(i=1;i<=n;i++)
{
for(j=0;j<L[i].size();j++)
Update(L[i][j], 1);
for(j=0;j<R[i].size();j++)
Update(R[i][j], -1);
last = 1;
for(j=1;j<=n/b[i];j++)
{
l = last, r = m+1;
while(l<r)
{
mid = (l+r)>>1;
if(Query(mid)<j*b[i])
l = mid+1;
else
r = mid;
}
//printf("%d\n", r);
if(r==m+1)
break;
A[r].push_back(i);
last = r+1;
}
}
ans = 0, len = n;
memset(tre, 0, sizeof(tre));
for(i=1;i<=m;i++)
{
for(j=0;j<A[i].size();j++)
Update(A[i][j], 1);
if(s[i].t==0)
printf("%d\n", Query(s[i].r)-Query(s[i].l-1));
A[i].clear();
}
for(i=1;i<=n;i++)
{
L[i].clear();
R[i].clear();
tre[i] = 0;
}
}
return 0;
}
/*
5 4
1 5 2 4 3
add 1 4
query 1 4
add 2 5
query 2 5
*/