bzoj1135 [POI2009]Lyz 霍尔定理+线段树

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/82501292

Description


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

n m k d ( 1≤n≤200,000 , 1≤m≤500,000 , 1≤k≤10^9 , 0≤d≤n ) ri xi ( 1≤i≤m, 1≤ri≤n-d , |xi|≤10^9 )

Solution


我们把脚和鞋看成是两排点跑网络流,若满流答案为TAK。显然这样过不了
考虑把与源点连边容量为x的点拆成x个连容量为1的边,那么变成是否满足脚的一侧全部有匹配点
然后上霍尔定理。注意到我们只需要找连续的一段判断即可,因为连边也是连续的一段
那么变成判断 i = l r x i ( r l + 1 + d ) × k 是否成立,我们移项可以得到 i = l r ( x i k ) d × k
于是变成求最大连续子段和,上线段树就可以了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)

using std:: max;

typedef long long LL;
const int N=200005;

LL ls[N<<2],rs[N<<2],s[N<<2],mx[N<<2];

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void update(LL &x,LL y) {
    (x<y)?(x=y):(0);
}

void push_up(int now) {
    s[now]=s[now<<1]+s[now<<1|1];
    ls[now]=max(ls[now<<1],s[now<<1]+ls[now<<1|1]);
    rs[now]=max(rs[now<<1|1],s[now<<1|1]+rs[now<<1]);
    mx[now]=mx[now<<1];
    update(mx[now],mx[now<<1|1]);
    update(mx[now],rs[now<<1]+ls[now<<1|1]);
}

void modify(int now,int tl,int tr,int x,LL v) {
    if (tl==tr) {
        s[now]+=v; mx[now]+=v;
        update(ls[now]=s[now],0);
        update(rs[now]=s[now],0);
        return ;
    }
    int mid=(tl+tr)>>1;
    (x<=mid)?(modify(now<<1,tl,mid,x,v)):(modify(now<<1|1,mid+1,tr,x,v));
    push_up(now);
}

int main(void) {
    int n=read(),m=read(); LL k=read(),d=read();
    rep(i,1,n) modify(1,1,n,i,-k); d=d*k;
    for (;m--;) {
        int x=read(),r=read();
        modify(1,1,n,x,r);
        (mx[1]<=d)?(puts("TAK")):(puts("NIE"));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/82501292
今日推荐