[2019长沙长郡中学集训]加法

mac2022-06-30  85

题面描述

给定一个\(n\)阶排列\(b\),要求维护一个初值全为\(0\)的数组\(\{a_i\}\),支持\(q\)次如下操作:

给出\(l,r\),将\(a_l,a_{l+1},......,a_{r-1},a_r\),全部+1

给出\(l,r\),查询\(\sum_{i=l}^{r} \lfloor \frac{{b[i]}}{a[i]} \rfloor\)

输入格式

第一行输入两个整数\(n,q\) 第二行\(n\)个正整数表示排列\(b\)。 接下来\(q\)行,每行三个正整数\(op,l,r,op=1\)表示第一种操作,\(op=2\)表示第二种操作

输出格式

对于每次询问,输出一行一个非负整数表示答案。

数据规模

对于$0 $的数据,\(1\leq n,q \leq 3000.\) 对于另外\(\0\)的数据,当\(op=2\)时,有\(l=1,r=n\) 对于\(\0\)的数据,\(1\leq n,q \leq 3\times 10^5,op\in\{1,2\},1\leq l \leq r \leq n.\)

样例输入

5 10 1 5 2 4 3 1 1 4 2 1 4 1 2 5 1 3 5 2 1 5 1 2 4 2 1 4 1 2 5 1 2 2 2 1 5

样例输出

1 2 4 6

题解

考试的时候爆掉了。。。卡常是真的恶心QAQ 先考虑部分分的做法 对于3000以内的数据,我们直接暴力循环。比较闲的同学可以考虑写两个线段树,一个用来更新a数组的值,另一个用来维护a[i]/b[i]。 对于查询操作恒查询整个区间的数据,我们可以只维护一个线段树,用于维护a数组,并区间查询整个区间的ans即可。 ---------------------------以下是正解部分----------------------------- 观察原式可以发现,我们最后的取值要向下取整,则每一个位置\(i\)产生更多贡献的唯一办法就是使a[i]成为b[i]的k倍(k>0)。因此,我们用一个线段树记录b[i]的值,用数组记录b的原值,同时用另一棵线段树维护答案,每次op=1时使区间内的每一个b[i]全部-1。当b[i]=0时我们使当前位的贡献+1,并重置b[i]的值为初始值。每次单独变换的复杂度为\(O(\log n)\),每次查询时递归进第二棵线段树中查找,因此总的复杂度是\(O(q \log^2n)\) 为什么要用减法而不是加法呢? 如果用加法运算我们需要同时维护maxa和minb的值,而如果用减法只用维护一个min就好了 #include<bits/stdc++.h> #define il inline #define re register typedef long long ll; using namespace std; const int maxn = 3e5 + 10; int n, q, ans; int b[maxn]; int trmin[maxn<<2], tradd[maxn<<2], lazy[maxn<<2]; // il void init() { memset(lazy, 0, sizeof(lazy)); memset(trmin, 0, sizeof(trmin)); memset(tradd, 0, sizeof(tradd)); } // il void pushup(int id) { trmin[id] = min(trmin[id<<1], trmin[id<<1|1]); tradd[id] = tradd[id<<1] + tradd[id<<1|1]; return ; } // il void build(int id, int l, int r) { if(l == r) { trmin[id] = b[l]; return; } int mid = (l+r)>>1; build(id<<1, l, mid); build(id<<1|1, mid+1, r); pushup(id); } il void pushdown(int id) { if (lazy[id]) { lazy[id << 1] += lazy[id]; lazy[id << 1 | 1] += lazy[id]; trmin[id << 1] -= lazy[id]; trmin[id << 1 | 1] -= lazy[id]; lazy[id] = 0; } } il void update(int id, int l, int r, int x, int y) { if(trmin[id] > 1 && x <= l && r <= y) { lazy[id]++; trmin[id]--; return ; } if(trmin[id] == 1 && l == r) { tradd[id]++; trmin[id] = b[l]; lazy[id] = 0; return ; } pushdown(id); int mid = (l + r) >> 1; if (x <= mid) update(id << 1, l, mid, x, y); if (y > mid) update(id << 1 | 1, mid + 1, r, x, y); pushup(id); } il int query(int id, int l, int r, int x, int y) { if(x <= l && r <= y) return tradd[id]; if(trmin[id] == 0) update(1, 1, n, x, y); pushdown(id); int sum = 0; int mid = (l+r) >> 1; if(x <= mid) sum += query(id<<1, l, mid, x, y); if(y > mid) sum += query(id<<1|1, mid+1, r, x, y); pushup(id); return sum; } signed main(){ init(); scanf("%d%d", &n, &q); for(re int i = 1; i <= n; ++i) scanf("%d", &b[i]); build(1, 1, n); int op, l, r; while(q--) { scanf("%d%d%d", &op, &l, &r); if(op == 1) update(1, 1, n, l, r); else printf("%d\n", query(1, 1, n, l, r)); } return 0; }

转载于:https://www.cnblogs.com/Chen574118090/p/11563154.html

最新回复(0)