【BZOJ】1135: [POI2009]Lyz

题意

\(1\)\(n(1 \le n \le 200000)\)号的溜冰鞋各\(k(1 \le k \le 10^9)\)双。已知\(x\)号脚的人可以穿\(x\)\(x+d\)的溜冰鞋。
\(m(1 \le m \le 500000)\)次操作,每次来了\(x_i\)\(r_i\)号脚的人。\(x_i\)为负,则代表走了这么多人。对于每次操作,输出溜冰鞋是否足够。

分析

容易发现是二分图模型,然而数据太大。

题解

根据Hall定理:如果存在\(X\)的完备匹配,则\(X\)中任意\(k\)个点都至少与\(Y\)中的\(k\)个点相邻。
所以我们只需要在任意一些人使得满足这个条件那么就行了。
然后来了个神结论:
假设\(a_i\)\(i\)号鞋的人,则只要任意的\([l, r]\)满足\(\sum_{i=l}^{r} a_i \ge (r-l+1+d) * k\),即\(\sum_{i=l}^{r} (a_i-k) \ge d * k\)则可行。
并不知道这个结论怎么来的...
所以用线段树维护一下最大子序列的值即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int getint() {
    int x=0, f=1, c=getchar();
    for(; c<48||c>57; f=c=='-'?-1:f, c=getchar());
    for(; c>47&&c<58; x=x*10+c-48, c=getchar());
    return x*f;
}
struct T {
    ll mx, mxl, mxr, s;
    void init() {
        mx=mxl=mxr=s;
    }
}t[1000005];
int n, m, k, d;
void up(int x) {
    int l=x<<1, r=x<<1|1;
    t[x].s=t[l].s+t[r].s;
    t[x].mxl=max(t[l].mxl, t[l].s+t[r].mxl);
    t[x].mxr=max(t[r].mxr, t[r].s+t[l].mxr);
    t[x].mx=max(t[l].mxr+t[r].mxl, max(t[l].mx, t[r].mx));
}
void upd(int p, int g, int l=1, int r=n, int x=1) {
    if(l==r) {
        t[x].s+=g;
        t[x].init();
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid) {
        upd(p, g, l, mid, x<<1);
    }
    else {
        upd(p, g, mid+1, r, x<<1|1);
    }
    up(x);
}
int main() {
    n=getint(), m=getint(), k=getint(), d=getint();
    for(int i=1; i<=n; ++i) {
        upd(i, -k);
    }
    for(ll te=(ll)d*k; m; --m) {
        int r=getint(), x=getint();
        upd(r, x);
        puts(t[1].mx<=te?"TAK":"NIE");
    }
    return 0;
}

转载于:https://www.cnblogs.com/iwtwiioi/p/4985664.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值