题意:
初始时滑冰俱乐部有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; }
时间: 2024-08-04 23:40:52