Description
初始时滑冰俱乐部有 (1) 到 (n) 号的溜冰鞋各 (k) 双。已知 (x) 号脚的人可以穿 (x) 到 (x+d) 的溜冰鞋。有 (m) 次操作,每次包含两个数 (r_i) , (x_i) 代表来了 (x_i) 个 (r_i) 号脚的人。 (x_i) 为负,则代表走了这么多人。 对于每次操作,输出溜冰鞋是否足够。
(1leq nleq 200,000,1leq mleq 500,000)
Solution
用 ( ext{Hall}) 定理以及贪心的思想,容易得到 (forall l,rin[1,n],lleq r)
[sum_{i=l}^rx_ileq k(r+d-l+1)]
移项,得到
[sum_{i=l}^r(x_i-k)leq k imes d]
显然只要有 ((x_i-k)) 最大子段和 (leq k imes 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; }