题意:给出两个序列a,b;a序列一开始为0,b序列为输入中给出的固定序列
有n次修改,l r k ,即在a的(l,r)区间内的元素全部加1。
在m次查询,l r 即询问在区间以内 的值
思路:区间修改已经区间维护就会想到线段树。但是怎样维护这棵树?由于b是固定的序列,且ai/bi还要向下取整
我们区间要修改即是 某个ai+1之后成为bi的倍数。但是仍不好判断,a的区间倒是修改了,但是ai/bi的取值还是要搜寻到
每个叶子结点去。 所以我们换一种 写法,ai+1同样可以表示为bi-1,当某个bi变为0了即ai就增加到这个bi的倍数去了
然后我们把这个bi又重置会原来的值,这样区间就可以维护了
我们开一个Min数组记录之前对bi修改后的状态最小值,如果该值为0,则说明这个区间就会使sum发生改变,那么我们在递归下去
找到Min[p] = 0的位置进行修改即可
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <algorithm> #define ll long long #define IOS ios::sync_with_stdio(0); cin.tie(0);using namespace std; using namespace std; const int maxn = 1e5+1; int Min[maxn<<2];//存储区间最小 ll sum[maxn<<2];//存储区间和 ll lazy[maxn<<2]; int arr[maxn]; int b[maxn]; void push_up(int p){ sum[p] = sum[p<<1] + sum[p<<1|1]; Min[p] = min(Min[p<<1],Min[p<<1|1]); } void push_down(int k) { if (lazy[k]) { lazy[k << 1] += lazy[k]; lazy[k << 1 | 1] += lazy[k]; Min[k << 1] -= lazy[k]; Min[k << 1 | 1] -= lazy[k]; lazy[k] = 0; } } void build(int p,int l,int r){ sum[p] = lazy[p] = 0; if(l==r) { Min[p] = b[l]; return ; } int mid = (l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); push_up(p); } //void dfs(int p,int l,int r){ // if(Min[p] != 0) return ; // if(l == r){ // sum[p]++; Min[p] = b[l]; // return ; // } // push_down(p); // int mid = (l+r)>>1; // if(Min[p<<1] == 0) dfs(p<<1,l,mid); // if(Min[p<<1|1] == 0) dfs(p<<1|1,mid+1,r); // push_up(p); //} void dfs(int rt, int l, int r) { if(Min[rt] != 0) return ; if(l == r) { sum[rt]++, Min[rt] = b[l]; return ; } push_down(rt); int mid = l+r>>1; if(Min[rt<<1] == 0) dfs(rt<<1, l, mid); if(Min[rt<<1|1] == 0) dfs(rt<<1|1, mid+1, r); push_up(rt); } void update(int p ,int l,int r,int L,int R){ int mid = (l+r)>>1; if(L<=l&&r<=R){ Min[p]--; lazy[p] += 1; if(Min[p]==0){ dfs(p,l,r); } return; } push_down(p); if(L<=mid) update(p<<1,l,mid,L,R); if(R>mid) update(p<<1|1,mid+1,r,L,R); push_up(p); } int query(int p,int l,int r,int ql,int qr){ int res = 0; if(ql<=l && r<=qr){ return sum[p]; } push_down(p); int mid = (l+r)>>1; if(ql<=mid) res += query(p<<1,l,mid,ql,qr); if(qr>mid) res += query(p<<1|1,mid+1,r,ql,qr); return res; } int main(){ IOS; int n,m; string s; while(cin>>n>>m){ int L,R; for(int i = 1;i<=n;i++){ cin>>b[i];//线段树默认从1开始记录 } build(1,1,n); for(int i = 0;i<m;i++){ cin>>s; if(s[0]=='a'){ cin>>L>>R; update(1,1,n,L,R); }else{ cin>>L>>R; cout<<query(1,1,n,L,R)<<endl; } } } }