CF1661 D. Progressions Covering (1900 线段树区间加等差数列)

https://codeforces.com/contest/1661/problem/D
题意: 给出初始全零的a数组,和b数组,每次操作可以选择完整的长度为k的一段加上1,2,3...k.问最学要多少次操作才能使所有ai都大于bi。
思路: 这里有一个比较强的限制:选择完整的长度k的一段修改,这就使得修改1的话必须选择[1, k],修改n的话必须选择[n - k + 1, n]。然后发现从后往前对于每个非0的bi,肯定把它当右边界修改最快。
所以总体思路就是:倒着扫一遍,考虑如何快速区间等差数列加:

  • 操作有区间修改,单点查询。 使用线段树维护,让val值为等差数列首项,lazy为公差,这样分裂时候左区间继承val和lazy,右区间的首项 :tree[rt].val + tree[rt].lazy * ( mid - l + 1); 单点修改不需要考虑合并。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define PII pair<int, int>
const int N = 3e5 + 5;
const int M = 1e7 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
ll a[N];
struct node {
   ll val, lazy;
}tree[N << 2];
void push_down( int l, int r, int rt ) {
   if(!tree[rt].val && !tree[rt].lazy) return;
   int mid = l + r >> 1;
   tree[rt << 1].val += tree[rt].val;
   tree[rt << 1 | 1].val += tree[rt].val + tree[rt].lazy * ( mid - l + 1);
   tree[rt << 1].lazy += tree[rt].lazy;
   tree[rt << 1 | 1].lazy += tree[rt].lazy;
   tree[rt].val = tree[rt].lazy = 0;
}
void modify ( int a, int b, ll st, ll d, int l, int r, int rt ) {
   if( r < a || l > b) return;
   if( l >= a && r <= b) {
       tree[rt].val += st +  d * (l - a);
       tree[rt].lazy += d;
       return;
   }
   int mid = l + r >> 1;
   push_down(l, r, rt);
   modify(a, b, st, d, l, mid, rt << 1);
   modify(a, b, st, d, mid + 1, r, rt << 1 | 1);
}
int query( int pos, int l, int r, int rt ) {
   if(l == r) return tree[rt].val;
   push_down( l, r, rt );
   int mid = l + r >> 1;
   if(pos <= mid) return query( pos, l, mid, rt << 1 );
   else return query(pos, mid + 1, r, rt << 1 | 1);
}
int main () {
   IOS
   int n, k; cin >> n >> k;
   for ( int i = 1; i <= n; ++ i ) cin >> a[i];
   ll ans  = 0;
   for ( int i = n; i >= 1; -- i ) {
       ll val = query(i, 1, n, 1);
       if( val >= a[i] ) continue;
       if(i - k  + 1 >= 1) {
           ll mul = (a[i] - val) / k + ((a[i] - val) % k != 0);
           modify(i - k + 1, i, mul, mul, 1, n, 1);
           ans += mul;
       } else {
           ll mul = (a[i] - val) / i + ((a[i] - val) % i != 0);
           modify(1, i, mul, mul, 1, n, 1);
           ans += mul;
       }
   }
   cout << ans << endl;

}
posted @ 2022-04-11 09:28  qingyanng  阅读(78)  评论(0编辑  收藏  举报