题目链接:Naive Operations
题意
有两个长度为 n n 的序列 和 b b , 是一个 1 1 到 的排列, a a 序列初始每个值都为 ,有 q q 次操作,每次操作为以下两种之一:
- :将区间 [l,r] [ l , r ] 内的所有数字都加上 1 1 ;
- :询问 ∑ri=l⌊aibi⌋ ∑ i = l r ⌊ a i b i ⌋ 的值。
输入
多组输入(不超过 5 5 组),每组输入第一行包含两个整数 ,接下去一行为 n n 个整数 ,序列 b b 是 到 n n 的一个排列,接下去 行每行为一个字符串和两个区间的端点 s l r (1≤l≤r≤n) s l r ( 1 ≤ l ≤ r ≤ n ) ,若 s=add s = a d d ,则执行操作 1 1 ,否则执行操作 ,
输出
对于每组询问,输出询问的答案。
样例
输入 |
---|
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 |
题解
由于每次操作都只对区间 +1 + 1 ,最坏情况下,如果每次操作都对整个区间 +1 + 1 ,那么 q q 次操作后区间的和为 ,因此对于每次 ⌊aibi⌋ ⌊ a i b i ⌋ 增加 1 1 时都更新一次(用树状数组更新复杂度为 ),这样区间更新就用区间增减区间最小值的线段树维护,线段树上每个数初始为 bi b i ,每次操作 1 1 就将区间 内的数字都 −1 − 1 ,每当区间最小值为 0 0 时就单点更新这个最小值,并将这个值赋值为 ,总的时间复杂度约为 O(2qlnnlogn) O ( 2 q ln n log n ) 。
过题代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <sstream>
using namespace std;
#define LL long long
const int maxn = 100000 + 100;
int n, q, x, y;
char str[20];
int num[maxn];
int Min[maxn << 2], lazy[maxn << 2];
int sum[maxn];
int lowbit(int x) {
return x & (-x);
}
void update(int Index, int x) {
while(Index <= n) {
sum[Index] += x;
Index += lowbit(Index);
}
}
int query(int Index) {
int ret = 0;
while(Index > 0) {
ret += sum[Index];
Index -= lowbit(Index);
}
return ret;
}
int query(int l, int r) {
return query(r) - query(l - 1);
}
void push_up(int rt) {
Min[rt] = min(Min[rt << 1], Min[rt << 1 | 1]);
}
void push_down(int rt) {
if(lazy[rt] != 0) {
lazy[rt << 1] += lazy[rt];
lazy[rt << 1 | 1] += lazy[rt];
Min[rt << 1] += lazy[rt];
Min[rt << 1 | 1] += lazy[rt];
lazy[rt] = 0;
}
}
void build(int l, int r, int rt) {
lazy[rt] = 0;
if(l == r) {
sum[l] = 0;
Min[rt] = num[l];
return ;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
push_up(rt);
}
void solve(int l, int r, int rt) {
if(l == r) {
update(l, 1);
Min[rt] = num[l];
return ;
}
push_down(rt);
int m = (l + r) >> 1;
if(Min[rt << 1] == 0) {
solve(l, m, rt << 1);
}
if(Min[rt << 1 | 1] == 0) {
solve(m + 1, r, rt << 1 | 1);
}
push_up(rt);
}
void update(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
--Min[rt];
--lazy[rt];
if(Min[rt] == 0) {
solve(l, r, rt);
}
return ;
}
push_down(rt);
int m = (l + r) >> 1;
if(L <= m) {
update(L, R, l, m, rt << 1);
}
if(m < R) {
update(L, R, m + 1, r, rt << 1 | 1);
}
push_up(rt);
}
int main() {
#ifdef Dmaxiya
freopen("test.txt", "r", stdin);
#endif // Dmaxiya
ios::sync_with_stdio(false);
while(scanf("%d%d", &n, &q) != EOF) {
for(int i = 1; i <= n; ++i) {
scanf("%d", &num[i]);
}
build(1, n, 1);
for(int i = 0; i < q; ++i) {
scanf("%s%d%d", str, &x, &y);
if(str[0] == 'a') {
update(x, y, 1, n, 1);
} else {
printf("%d\n", query(x, y));
}
}
}
return 0;
}