初始时滑冰俱乐部有 \(1\) 到 \(n\) 号的溜冰鞋各 \(k\) 双。已知 \(x\) 号脚的人能够穿 \(x\) 到 \(x+d\) 的溜冰鞋。php
有 \(m\) 次操做,每次包含两个数 \(r_i,x_i\) 表明来了 \(x_i\) 个 \(r_i\) 号脚的人。\(x_i\) 为负,则表明走了这么多人。 对于每次操做,输出溜冰鞋是否足够。足够输出 TAK
, 不然输出 NIE
.c++
\(n\le 2\times 10^5,m\le5\times 10^5,k\le1\times 10^9,d\in[0,n],1\le r_i\le n-d,|x_i|\le1\times 10^9\)this
被某Robbery少量增强后丢到了胡策里...spa
由霍尔定理, 二分图存在完美匹配当且仅当一侧的任意一个子集中的点链接的另外一侧的点的数量都不小于这个子集的大小. 虽然看上去要枚举子集可是实际上咱们发现不连续的几段更有可能知足霍尔定理的要求, 因此只要连续区间都知足霍尔定理的要求那么全部子集就都知足了. 感性证实以下:code
假设选中了一个不连续的子集, 那么显然能够在不改变另一侧的邻接状况下在当前子集中添加新的点. 若是不能添加新的点的话能够把子集拆成若干部分, 每一个部分是一个连续段. 显然拆开后或者添加新点后更可能会破坏霍尔定理的要求.blog
也就是说若是设 \(i\) 号脚的人共有 \(s_i\) 个, 那么溜冰鞋不足当且仅当存在任意一个区间 \([l,r]\) 知足下式:
\[ \sum_{i=l}^rs_i>k(r-l+d+1) \]
那么咱们拆开移项就能够获得:
\[ \begin{aligned} \sum_{i=l}^rs_i-k(r-l+1)&>kd \\ \sum_{i=1}^r(s_i-k)&>kd \end{aligned} \]
因而就变成了一个支持单点加法的动态区间最大子段和问题. 线段树动态DP经典操做.get
增强版里不保证 \(r\le n-d\), 须要继续考虑 \(r>n-d\) 的状况. 此时溜冰鞋不足的充要条件至关于:
\[ \sum_{i=l}^rs_i>k(n-l+1) \]
显然当 \(r=n\) 的时候左侧取到最大值, 咱们只计算 \(r=n\) 时是否知足条件便可. 此时至关于:
\[ \sum_{i=l}^ns_i>k(n-l+1) \]
设 \(S\) 是 \(\langle s_i\rangle\) 的前缀和, 那么咱们能够发现上式等价于:
\[ \begin{aligned} S_n-S_{l-1}&>kn-k(l-1) \\ k(l-1)-S_{l-1}&>kn-S_n \end{aligned} \]
左侧的最大值显然也能够用线段树维护出来.it
#include <bits/stdc++.h> const int MAXN=1e5+10; typedef long long intEx; struct Node{ struct Data{ intEx sum; intEx lmax; intEx maxs; intEx rmax; Data(){} Data(intEx val){ this->sum=val; this->lmax=this->rmax=this->maxs=std::max(this->sum,0ll); } Data friend operator+(const Data& a,const Data& b){ Data ans; ans.sum=a.sum+b.sum; ans.lmax=std::max(a.lmax,a.sum+b.lmax); ans.rmax=std::max(a.rmax+b.sum,b.rmax); ans.maxs=std::max(a.rmax+b.lmax,std::max(a.maxs,b.maxs)); return ans; } }; int l; int r; Data val; Node* lch; Node* rch; Node(int,int); void Maintain(); void Add(int,int); }; int n; int q; int k; int d; int main(){ scanf("%d%d%d%d",&n,&q,&k,&d); Node* N=new Node(1,n); for(int i=0;i<q;i++){ int p,x; scanf("%d%d",&p,&x); N->Add(p,x); if(N->val.maxs>1ll*k*d) puts("NIE"); else puts("TAK"); } return 0; } Node::Node(int l,int r):l(l),r(r){ if(l==r) this->val=Data(-k); else{ int mid=(l+r)>>1; this->lch=new Node(l,mid); this->rch=new Node(mid+1,r); this->Maintain(); } } void Node::Add(int x,int d){ if(this->l==this->r) this->val=Data(this->val.sum+d); else{ if(x<=this->lch->r) this->lch->Add(x,d); else this->rch->Add(x,d); this->Maintain(); } } inline void Node::Maintain(){ this->val=this->lch->val+this->rch->val; }
增强版写的比较蠢...写了一个维护最大子段和的和一个区间加法区间最值的线段树...class
#include <bits/stdc++.h> const int MAXN=1e5+10; typedef long long intEx; struct Node{ struct Data{ intEx sum; intEx lmax; intEx maxs; intEx rmax; Data(){} Data(intEx val){ this->sum=val; this->lmax=this->rmax=this->maxs=std::max(this->sum,0ll); } Data friend operator+(const Data& a,const Data& b){ Data ans; ans.sum=a.sum+b.sum; ans.lmax=std::max(a.lmax,a.sum+b.lmax); ans.rmax=std::max(a.rmax+b.sum,b.rmax); ans.maxs=std::max(a.rmax+b.lmax,std::max(a.maxs,b.maxs)); return ans; } }; int l; int r; Data val; Node* lch; Node* rch; Node(int,int); void Maintain(); void Add(int,int); }; struct NodeX{ int l; int r; intEx add; intEx max; NodeX* lch; NodeX* rch; NodeX(int,int); void PushDown(); void Maintain(); void Add(int,int,int); void Add(const intEx&); }; int n; int q; int k; int d; int main(){ scanf("%d%d%d%d",&n,&q,&k,&d); Node* N=new Node(1,n); NodeX* K=new NodeX(0,n-1); for(int i=0;i<q;i++){ int p,x; scanf("%d%d",&p,&x); N->Add(p,x); if(p!=n) K->Add(p,n-1,-x); // printf("%lld %lld\n",N->val.maxs,K->max); if(N->val.maxs>1ll*k*d||K->max>-N->val.sum) puts("No"); else puts("Yes"); } return 0; } NodeX::NodeX(int l,int r):l(l),r(r),add(0){ if(l==r) this->max=1ll*l*k; else{ int mid=(l+r)>>1; this->lch=new NodeX(l,mid); this->rch=new NodeX(mid+1,r); this->Maintain(); } } void NodeX::Add(const intEx& d){ this->add+=d; this->max+=d; } void NodeX::Add(int l,int r,int d){ if(l<=this->l&&this->r<=r) this->Add(d); else{ this->PushDown(); if(l<=this->lch->r) this->lch->Add(l,r,d); if(this->rch->l<=r) this->rch->Add(l,r,d); this->Maintain(); } } void NodeX::PushDown(){ if(this->add){ this->lch->Add(this->add); this->rch->Add(this->add); this->add=0; } } void NodeX::Maintain(){ this->max=std::max(this->lch->max,this->rch->max); } Node::Node(int l,int r):l(l),r(r){ if(l==r) this->val=Data(-k); else{ int mid=(l+r)>>1; this->lch=new Node(l,mid); this->rch=new Node(mid+1,r); this->Maintain(); } } void Node::Add(int x,int d){ if(this->l==this->r) this->val=Data(this->val.sum+d); else{ if(x<=this->lch->r) this->lch->Add(x,d); else this->rch->Add(x,d); this->Maintain(); } } inline void Node::Maintain(){ this->val=this->lch->val+this->rch->val; }