zoukankan      html  css  js  c++  java
  • [cf 1136] E. Nastya Hasn't Written a Legend

    题意

    给两个数组分别为(a)(k),有若干次操作:

    1.给(a_x)加上(y),并以此对(a_{x + i}(i ge 1))赋值为(max {a_{x + i}, a_{x + i - 1} + k_{x + i - 1}})

    2.询问区间([l, r])(a_i)的和。

    题解

    自闭了啊。

    考虑把原序列分成若干个块,对于每个块内必须满足,除最后一个位置的所有位置(i)(a_i + k_i = a_i + 1)。刚开始可以看成有(n)个块。

    每次修改的时候,直接对每个块内用线段树修改,块与块之间可能有合并(最多合并(O(n + q))次),然后每一次修改可能会产生(O(1))个新的块。所有块用一个set维护一下。所以总复杂度是(O((n + q) log n))的。

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define mp make_pair
    using namespace std;
    typedef long long ll;
    typedef pair <int, int> pii;
     
    inline int read () {
    	static int x;
    	scanf("%d", &x);
    	return x;
    }
    const int N = 1e5 + 5, inf = 2e9;
    int n, q, a[N], k[N]; ll pres[N];
    set <pii> block;
    ll s[N << 2], tag[N << 2];
    #define mid ((l + r) >> 1)
    #define lc (o << 1)
    #define rc (o << 1 | 1)
    #define ls lc, l, mid
    #define rs rc, mid + 1, r
    inline void pushdown (int o, int l, int r) {
    	s[lc] += tag[o] * (mid - l + 1), tag[lc] += tag[o];
    	s[rc] += tag[o] * (r - mid), tag[rc] += tag[o];
    	tag[o] = 0;
    }
    inline void build (int o, int l, int r) {
    	if (l == r) {s[o] = a[l]; return;}
    	build(ls), build(rs);
    	s[o] = s[lc] + s[rc];
    }
    inline void modify (int o, int l, int r, int x, int y, ll v) {
    	if (x <= l && r <= y) {s[o] += v * (r - l + 1), tag[o] += v; return;}
    	if (tag[o]) pushdown(o, l, r);
    	if (x <= mid) modify(ls, x, y, v);
    	if (y > mid) modify(rs, x, y, v);
    	s[o] = s[lc] + s[rc];
    }
    inline ll query (int o, int l, int r, int x, int y) {
    	if (x <= l && r <= y) return s[o];
    	if (tag[o]) pushdown(o, l, r);
    	ll ret = 0;
    	if (x <= mid) ret += query(ls, x, y);
    	if (y > mid) ret += query(rs, x, y);
    	return ret;
    }
    
    void alter (int x, int v) {
    	set <pii> :: iterator b; int l, r;
    	b = block.lower_bound(mp(x, inf)), --b;
    	l = b->fi, r = b->se;
    	block.erase(b);
    	if (l < x) block.insert(mp(l, x - 1));
    	modify(1, 1, n, x, r, v);
    	for ( ; r < n; ) {
    		ll s = query(1, 1, n, r, r), t = query(1, 1, n, r + 1, r + 1), delta = s + k[r] - t;
    		if (delta < 0) break;
    		b = block.lower_bound(mp(r + 1, r + 1));
    		l = b->fi, r = b->se;
    		block.erase(b);
    		modify(1, 1, n, l, r, delta);
    	}
    	block.insert(mp(x, r));
    }
    int main() {
    	n = read();
    	for (int i = 1; i <= n; ++i)
    		a[i] = read(), pres[i] = pres[i - 1] + a[i];
    	for (int i = 1; i < n; ++i) k[i] = read();
    	for (int i = 1; i <= n; ++i) block.insert(mp(i, i));
    	build(1, 1, n);	
    	char op[5]; int x, y;
    	for (int _ = read(); _; --_) {
    		scanf("%s", op), x = read(), y = read();
    		if (op[0] == '+') alter(x, y); else
    		printf("%lld
    ", query(1, 1, n, x, y));
    	}
    	return 0;
    }
    
  • 相关阅读:
    v-for
    class样式绑定
    数据单向绑定(v-bind:)和数据的双向绑定(v-model)
    v-on 事件修饰符
    C++中相对路径与绝对路径以及斜杠与反斜杠的区别(转)
    计算机图形学—判断点在直线上的方法(转)
    Eclipse XML/HTML语法高亮方法
    虚拟机 ubuntu 上网的配置过程
    VirtualBox虚拟机网络设置(四种方式)(转)
    查看Linux服务器网络状态(转)
  • 原文地址:https://www.cnblogs.com/psimonw/p/10727393.html
Copyright © 2011-2022 走看看