bzoj-1135 Lyz

141 篇文章 0 订阅
88 篇文章 0 订阅

题意:

初始时滑冰俱乐部有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;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值