[POI 2009]Lyz

Description

题库链接

初始时滑冰俱乐部有 $1$ 到 $n$ 号的溜冰鞋各 $k$ 双。已知 $x$ 号脚的人可以穿 $x$ 到 $x+d$ 的溜冰鞋。有 $m$ 次操作,每次包含两个数 $r_i$ , $x_i$ 代表来了 $x_i$ 个 $r_i$ 号脚的人。 $x_i$ 为负,则代表走了这么多人。 对于每次操作,输出溜冰鞋是否足够。

$1\leq n\leq 200,000,1\leq m\leq 500,000$

Solution

用 $\text{Hall}$ 定理以及贪心的思想,容易得到 $\forall l,r\in[1,n],l\leq r$

$$\sum_{i=l}^rx_i\leq k(r+d-l+1)$$

移项,得到

$$\sum_{i=l}^r(x_i-k)\leq k\times d$$

显然只要有 $(x_i-k)$ 最大子段和 $\leq k\times d$ 。线段树维护即可。

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 200000+5;

int n, m, k, d, x, r;
struct node {
    ll mx, l, r, sum;
    node (ll _mx = 0, ll _l = 0, ll _r = 0, ll _sum = 0) {
        mx = _mx, l = _l, r = _r, sum = _sum;
    }
    node operator + (const node &b) const {
        node ans;
        ans.l = max(l, sum+b.l); ans.r = max(b.r, b.sum+r);
        ans.sum = sum+b.sum; ans.mx = max(r+b.l, max(mx, b.mx));
        return ans;
    }
} ;
struct Segment_tree {
#define lr(o) (o<<1)
#define rr(o) (o<<1|1)
    node key[N<<2];
    void build(int o, int l, int r) {
        if (l == r) {key[o] = node(-k, -k, -k, -k); return; }
        int mid = (l+r)>>1;
        build(lr(o), l, mid), build(rr(o), mid+1, r);
        key[o] = key[lr(o)]+key[rr(o)];
    }
    void modify(int o, int l, int r, int loc, int val) {
        if (l == r) {
            ll t = key[o].sum+val;
            key[o] = node(t, t, t, t);
            return;
        }
        int mid = (l+r)>>1;
        if (loc <= mid) modify(lr(o), l, mid, loc, val);
        else modify(rr(o), mid+1, r, loc, val);
        key[o] = key[lr(o)]+key[rr(o)];     
    }
} T;

void work() {
    scanf("%d%d%d%d", &n, &m, &k, &d);
    T.build(1, 1, n);
    while (m--) {
        scanf("%d%d", &r, &x);
        T.modify(1, 1, n, r, x);
        puts(T.key[1].mx <= 1ll*k*d ? "TAK" : "NIE");
    }
}
int main() {work(); return 0; }
posted @ 2018-07-14 20:08  NaVi_Awson  阅读(204)  评论(0编辑  收藏  举报