[BZOJ 1135][POI2009]Lyz

题意

初始时滑冰俱乐部有 \(1\) 到 \(n\) 号的溜冰鞋各 \(k\) 双。已知 \(x\) 号脚的人可以穿 \(x\) 到 \(x+d\) 的溜冰鞋。

有 \(m\) 次操作,每次包含两个数 \(r_i,x_i\) 代表来了 \(x_i\) 个 \(r_i\) 号脚的人。\(x_i\) 为负,则代表走了这么多人。 对于每次操作,输出溜冰鞋是否足够。足够输出 TAK, 否则输出 NIE.

\(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\)

题解

被某Robbery少许加强后丢到了胡策里...

由霍尔定理, 二分图存在完美匹配当且仅当一侧的任意一个子集中的点连接的另一侧的点的数量都不小于这个子集的大小. 虽然看上去要枚举子集但是实际上我们发现不连续的几段更有可能满足霍尔定理的要求, 所以只要连续区间都满足霍尔定理的要求那么所有子集就都满足了. 感性证明如下:

假设选中了一个不连续的子集, 那么显然可以在不改变另外一侧的邻接情况下在当前子集中添加新的点. 如果不能添加新的点的话可以把子集拆成若干部分, 每个部分是一个连续段. 显然拆开后或者添加新点后更可能会破坏霍尔定理的要求.

也就是说如果设 \(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经典操作.

加强版里不保证 \(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}
\]

左侧的最大值显然也可以用线段树维护出来.

参考代码

#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;
}

加强版写的比较蠢...写了一个维护最大子段和的和一个区间加法区间最值的线段树...

#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;
}

[BZOJ 1135][POI2009]Lyz的更多相关文章

  1. bzoj 1135 [POI2009]Lyz 线段树+hall定理

    1135: [POI2009]Lyz Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 573  Solved: 280[Submit][Status][ ...

  2. 1135: [POI2009]Lyz

    1135: [POI2009]Lyz https://lydsy.com/JudgeOnline/problem.php?id=1135 分析: hall定理+线段树连续区间的最大的和. 首先转化为二 ...

  3. 【BZOJ】1135: [POI2009]Lyz

    题意 有\(1\)到\(n(1 \le n \le 200000)\)号的溜冰鞋各\(k(1 \le k \le 10^9)\)双.已知\(x\)号脚的人可以穿\(x\)到\(x+d\)的溜冰鞋. 有 ...

  4. BZOJ1135: [POI2009]Lyz

    1135: [POI2009]Lyz Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 264  Solved: 106[Submit][Status] ...

  5. 【BZOJ1135】[POI2009]Lyz 线段树

    [BZOJ1135][POI2009]Lyz Description 初始时滑冰俱乐部有1到n号的溜冰鞋各k双.已知x号脚的人可以穿x到x+d的溜冰鞋. 有m次操作,每次包含两个数ri,xi代表来了x ...

  6. BZOJ 1115: [POI2009]石子游戏Kam

    1115: [POI2009]石子游戏Kam Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 883  Solved: 545[Submit][Stat ...

  7. BZOJ 1142: [POI2009]Tab

    1142: [POI2009]Tab Time Limit: 40 Sec  Memory Limit: 162 MBSubmit: 213  Solved: 80[Submit][Status][D ...

  8. bzoj 1133: [POI2009]Kon dp

    1133: [POI2009]Kon Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 242  Solved: 81[Submit][Status][D ...

  9. bzoj 1138: [POI2009]Baj 最短回文路 dp优化

    1138: [POI2009]Baj 最短回文路 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 161  Solved: 48[Submit][Sta ...

随机推荐

  1. 第一次项目上Linux服务器(八:——搭建Nginx图片服务器)

    一.准备工作 安装Nginx,参考历史博客 二.搭建Nginx图片服务器 1.效果 例如:图片通过xftp服务上传到/home/java/upload目录下,我想通过访问Nginx服务器来访问xftp ...

  2. MWeb 生成静态网站&博客

    MWeb 生成静态网站 & 博客 MWeb 的静态网站分类 在 MWeb 的文档库中,有两种分类,一种是普通分类,另一种就是静态网站分类了.你可以直接新增一个静态网站分类,也可以在普通分类的顶 ...

  3. 如何判断JavaScript数据具体类型

    昨晚做了阿里的题目,让我写一个函数,可以判断数据的具体类型.其实题目很简单的...但是真的是自己不太注意吧,写的很糟糕啊. 然后今天就自己写了一个,然后又到晚上搜了下,看看别人的写法,结果发现自己有点 ...

  4. Microsoft Office MIME Types

    经常需要查找Microsoft Office MIME Types,终于在MSDN网上找到,摘录如下,以备查阅与参考:http://blogs.msdn.com/b/vsofficedeveloper ...

  5. VB.NET的MsgBox

    一.可用按钮(指定消息框显示哪些按钮) MsgBoxStyle.OkOnly = vbOKOnly = 0(确定按钮) MsgBoxStyle.OkCancel = vbOKCancel = 1(确定 ...

  6. [bug]不包含“AsNoTracking”的定义

    摘要 在使用ef做查询优化的时候我们会用到AsNoTracking方法,但如果不引入命名空间,你就会出现不包含“AsNoTracking”的定义的错误. 解决办法 引入命名空间:System.Data ...

  7. 自定义一个可以动态折叠的UITAbleViewCell

    看到code 4APP上有一个折叠的UITAbleViewCell,不过是swift的,所以自己尝试做一个简单的可折叠的UITAbleViewCell 主要实现一个可以折叠的UITAbleViewCe ...

  8. linux 安装mysql8.0

    linux下安装mysql8.0 下载mysql $ wget http://mirrors.ustc.edu.cn/mysql-ftp/Downloads/MySQL-8.0/mysql-8.0.4 ...

  9. 【Java并发编程】4、JDK7中TransferQueue的使用以及TransferQueue与SynchronousQueue的差别

    转自:http://blog.csdn.net/aitangyong/article/details/46472643 JDK7对JDK5中的J.U.C并发工具进行了增强,其中之一就是新增了Trans ...

  10. Windows平台如何部署scrapy

    0.安装Anaconda 这个不教了,自己去Anaconda官网上下个安装包,装上就好. https://www.anaconda.com/distribution/ 1.使用Anaconda创建一个 ...