题意:
初始时滑冰俱乐部有1到n号的溜冰鞋各k双,x号脚的人可以穿x到x+d的溜冰鞋,;
有m次操作,每次包含两个数ri,xi,代表来了xi个ri号脚的人(xi可能为负);
对于每次操作,输出溜冰鞋是否足够;
n<=200000,m<=500000,k<=10^9;
题解:
首先这是一个二分图匹配问题,显然鞋和人是没有交集的;
然后就有一个Hall定理:
二部图G中的两部分顶点组成的集合分别为X, Y;
边集中有一组无公共点的边,一端恰好为组成X的所有点的充分必要条件是:
X中的任意k个点至少与Y中的k个点相邻;(1≤k≤m)
相邻指有边相连,在x中任选k个我们用任选一段区间代替;
所以在一段区间[l,r]中,令x号脚的人数为F(x);
有∑F(i)<=(r-l+d+1)*k (l<=i<=r)成立;
将每个F(i)都减一个k,不等式可化为;
∑(F(i)-k)<=d*k (l<=i<=r);
这个式子任选一段区间都成立;
那么只要求出最大区间和判断是否大于d*k就可以了;
线段树维护,复杂度O(mlogn);
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 210000
#define lson l,mid,no<<1
#define rson mid+1,r,no<<1|1
using namespace std;
typedef long long ll;
struct Seg
{
ll L,R,ma,sum;
Seg(){}
Seg(ll x){L=R=ma=sum=x;}
friend Seg operator +(Seg l,Seg r)
{
Seg ret;
ret.sum=l.sum+r.sum;
ret.L=max(l.L,l.sum+r.L);
ret.R=max(r.R,r.sum+l.R);
ret.ma=max(l.R+r.L,max(l.ma,r.ma));
return ret;
}
}tr[N<<2];
void Pushup(ll no)
{
tr[no]=tr[no<<1]+tr[no<<1|1];
}
void Build(ll l,ll r,ll no,ll k)
{
if(l==r)
tr[no]=Seg(-k);
else
{
ll mid=l+r>>1;
Build(lson,k);
Build(rson,k);
Pushup(no);
}
}
void update(ll l,ll r,ll no,ll x,ll val)
{
if(l==r)
tr[no]=Seg(tr[no].sum+val);
else
{
ll mid=l+r>>1;
if(x<=mid) update(lson,x,val);
else update(rson,x,val);
Pushup(no);
}
}
int main()
{
ll n,m,d,i,j,k,x,r;
scanf("%lld%lld%lld%lld",&n,&m,&k,&d);
Build(1,n,1,k);
for(i=1;i<=m;i++)
{
scanf("%lld%lld",&r,&x);
update(1,n,1,r,x);
if(tr[1].ma>(ll)d*k)
puts("NIE");
else
puts("TAK");
}
return 0;
}