题意:
一段序列每一个元素有一个分母值和一个分子值,初始分子值为 0 ,给定一个分母值,可以进行以下操作:
1. add l r : add one for al,al+1...aral,al+1...ar 从 l 到 r 每个元素分子值加 1。
2. query l r : query ∑ri=l⌊ai/bi⌋ 询问从 l 到 r 区间内分子除以分母的和。
题解:
用一颗线段树来维护每次操作,由于如果叶子节点分子大于分母,那么该叶子节点的 ai / bi = 0 ,所以可以在每个区间节点保存该区间最小的 b 值然后每访问一次 b 值就减一,直到 b 值为 0 才继续往下更新,则 lazy 标记就是往下推需要减的 b 值,如果找到叶子节点并且该节点减为 0 那么该节点 b 值更新为原来的 b 值并更新答案。这样就可以在时间上进行优化。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#include<string>
#define INF 0x3f3f3f3f
#define MAXM 5000 + 10
#define MAXN 100000 + 10
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
struct node{
int mi, sum, add;
}T[MAXN<<2];
int a[MAXN];
void Push(int l, int r, int rt)//将标记向后推
{
if(T[rt].add != 0){
int mid = (l + r) >> 1;
T[rt<<1].mi += T[rt].add;
T[rt<<1|1].mi += T[rt].add;
T[rt<<1].add += T[rt].add;
T[rt<<1|1].add += T[rt].add;
T[rt].add = 0;
}
}
void Build(int l, int r, int rt)//建树
{
if(l == r){
T[rt].mi = a[l];
T[rt].add = 0;
T[rt].sum = 0;
return;
}
ll mid = (l + r) >> 1;
Build(l, mid, rt << 1);
Build(mid+1, r, rt << 1 | 1);
T[rt].mi = min(T[rt<<1].mi, T[rt<<1|1].mi);
T[rt].sum = T[rt<<1].sum + T[rt<<1|1].sum;
T[rt].add = T[rt<<1].add + T[rt<<1|1].add;
}
void Update(int L, int R, int l, int r, int rt, bool ok)//更新
{
if(L <= l && r <= R){
if(ok){
T[rt].add --;
T[rt].mi --;
}
if(T[rt].mi > 0) return ;
if(l == r){
if(T[rt].mi == 0) T[rt].sum ++, T[rt].mi = a[l];
return ;
}
ok = false;
}
Push(l, r, rt);
ll mid = (l + r) >> 1;
if(L <= mid) Update(L, R, l, mid, rt << 1, ok);
if(R > mid) Update(L, R, mid + 1, r, rt << 1 | 1, ok);
T[rt].mi = min(T[rt<<1].mi, T[rt<<1|1].mi);
T[rt].sum = T[rt<<1].sum + T[rt<<1|1].sum;
}
int Query(int L, int R, int l, int r, int rt)//查询
{
if(L <= l && r <= R) return T[rt].sum;
int mid = (l + r) >> 1;
int ans = 0;
if(L <= mid)
ans += Query(L, R, l, mid, rt << 1);
if(R > mid)
ans += Query(L, R, mid + 1, r, rt << 1 | 1);
return ans;
}
int main()
{
int n, q;
while(~scanf("%d %d", &n, &q)){
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
Build(1, n, 1);
for(int i = 1; i <= q; i ++){
char s[10]; scanf("%s", s);
int x, y; scanf("%d %d", &x, &y);
if(s[0] == 'a') Update(x, y, 1, n, 1, true);
if(s[0] == 'q')
printf("%d\n", Query(x, y, 1, n, 1));
}
}
}
/*
The WAM is F**KING interesting .
*/
1426

被折叠的 条评论
为什么被折叠?



