[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. [转]TFS常用的命令行详解

    本文转自:http://blchen.com/tfs-common-commands/ 微软的TFS和Visual Studio整合的非常好,但是在开发过程中,很多时候只用GUI图形界面就会发现一些复 ...

  2. Spring Security基本配置

    Spring Security 是一个功能强大且可高度自定义的身份验证和访问控制框架. 它是保护基于Spring的应用程序的事实上的标准.Spring Security 是一个专注于为Java应用程序 ...

  3. Table转换成实体、Table转换成实体集合(可转换成对象和值类型)

    /// <summary> /// Table转换成实体 /// </summary> /// <typeparam name="T">< ...

  4. 临时表 on commit delete rows 与 on commit preserve rows 的区别

    -- 事务级临时表:提交时删除数据 create global temporary  table tmp_table1 (        x     number ) on commit delete ...

  5. __int64 与long long 的区别

    //为了和DSP兼容,TSint64和TUint64设置成TSint40和TUint40一样的数 //结果VC中还是认为是32位的,显然不合适 //typedef signed long int    ...

  6. Number Sequence(hdu4390)

    Number Sequence Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Tot ...

  7. Java反射的好处

    反射的好处 我们在第一次接触反射的时候,总会有个很大的疑问,反射看起来好麻烦啊,各种get.get,他究竟有什么好处,能用来做什么呢? 我们先来看一下<编程思想>这本书中是怎么说的. RT ...

  8. TCP连接与OKHTTP复用连接池

    Android网络编程(八)源码解析OkHttp后篇[复用连接池] 1.引子 在了解OkHttp的复用连接池之前,我们首先要了解几个概念. TCP三次握手 通常我们进行HTTP连接网络的时候我们会进行 ...

  9. putty连接ubuntu:network error:connection refused

    原因: ubuntu存在一个bug:在/var/run/目录下缺少一个文件夹sshd 解决方法: 在命令行输入: sudo mkdir /var/run/sshd sudo /usr/sbin/ssh ...

  10. 设计模式(15)--Interpreter(解释器模式)--行为型

    作者QQ:1095737364    QQ群:123300273     欢迎加入! 1.模式定义: 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解 ...