Step1 Problem:
给你 n 个数,数组 a[] 初始化为 0,给你数组 b[](n 的全排列),进行 q 次操作,每次操作分为:
add L R: 数组 a[] 区间 L 到 R 的值都加 1
query L R:求区间 L 到 R,a[i]/b[i] 的和
数据范围:
1 <= n <= 1e5, 1 <= q <= 1e5, 1 <= L, R <= n.
Step2 Ideas:
对于每个 i,想要有贡献就需要 a[i] > b[i],相当于 i 这个位置需要 add b[i] 次就贡献 1,那么我们让 a[i] 初始为 b[i],每 add 一次 a[i] - 1,当 a[i] = 0 的时候就贡献了 1,再让 a[i] 变为 b[i]。核心点是想到减法,比赛用的加法然后mod b[i],结果怎么优化都超时
核心的两个条件:数组 b[] 是全排列,add 每次只加 1。
假设 n = 1e5, q = 1e5. 每次 add 区间 1~n,
贡献次数 = q/1 + q/2 + q/3 + q/4 + … + q/n,这个数和 n*log(n) 差不多。
所以我们可以维护区间最小值和区间减法,当最小值 = 0 的时候,我们就更新贡献值同时将 0 变为 b[i](更新次数也就 n*log(n) 次)。
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
#define lson root<<1
#define rson root<<1|1
#define MID int mid = (l+r)/2
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
struct node
{
int ans, Min, lazy;
};
node tree[N<<2];
int a[N], n;
node Merge(node x, node y)
{
node t;
t.Min = min(x.Min, y.Min);
t.ans = x.ans + y.ans;
t.lazy = 0;
return t;
}
void creat(int root, int l, int r)
{
tree[root].lazy = 0;
if(l == r) {
tree[root].ans = 0;
tree[root].Min = a[l];
return ;
}
MID;
creat(lson, l, mid);
creat(rson, mid+1, r);
tree[root] = Merge(tree[lson], tree[rson]);
}
void pushdown(int root, int l, int r)
{
if(tree[root].lazy) {
tree[lson].lazy += tree[root].lazy;
tree[lson].Min -= tree[root].lazy;
tree[rson].lazy += tree[root].lazy;
tree[rson].Min -= tree[root].lazy;
tree[root].lazy = 0;
}
}
void updata(int root, int l, int r, int L, int R)
{
if(L <= l && r <= R)
{
tree[root].Min--;
tree[root].lazy++;
return ;
}
pushdown(root, l, r);
MID;
if(mid >= L) updata(lson, l, mid, L, R);
if(mid < R) updata(rson, mid+1, r, L, R);
tree[root] = Merge(tree[lson], tree[rson]);
}
void updata_Min(int root, int l, int r)
{
if(l == r) {
tree[root].Min = a[l];
tree[root].ans++;
return;
}
MID;
pushdown(root, l, r);
if(tree[lson].Min < tree[rson].Min) updata_Min(lson, l, mid);
else updata_Min(rson, mid+1, r);
tree[root] = Merge(tree[lson], tree[rson]);
}
int query(int root, int l, int r, int L, int R)
{
if(L <= l && r <= R)
{
return tree[root].ans;
}
int ret = 0;
MID;
if(mid >= L) ret += query(lson, l, mid, L, R);
if(mid < R) ret += query(rson, mid+1, r, L, R);
return ret;
}
void show()
{
for(int i = 1; i <= 4*n; i++)
printf("%d %d %d\n", tree[i].ans, tree[i].lazy, tree[i].ans);
}
int main()
{
int m;
while(~scanf("%d %d", &n, &m))
{
for(int i = 1; i <= n; i++)
scanf("%d", a+i);
creat(1, 1, n);
//show();
char ok[15];
int L, R;
while(m--)
{
scanf("%s %d %d", ok, &L, &R);
if(ok[0] == 'a') {
updata(1, 1, n, L, R);
while(tree[1].Min == 0) {
updata_Min(1, 1, n);
}
}
else if(ok[0] == 'q') {
printf("%d\n", query(1, 1, n, L, R));
}
}
}
return 0;
}