【BZOJ2138】stone Hall定理+线段树
【BZOJ2138】stone
Description
Input
Output
有M行,第i行表示第i分钟最多能取多少石子。
Sample Input
3 2 4 7
3
2 5 2 6 4 9
2 4
1 2
3 5
Sample Output
5
5
【样例说明】
石子每堆个数分别为0,5,2,5,0。
第1分钟,从第2到第4堆中选2个;
第2分钟,从第1到第2堆中选5个;
第3分钟,从第3到第5堆中选8个,但最多只能选5个。
题解:如果把每堆石子拆成$A_i$个,将询问拆成$K_i$个,则原题可看成一个二分图最大匹配的模型。这里要应用到Hall定理。
Hall定理:两个集合$X$和$Y$进行匹配,最大匹配为$|X|$的充要条件是:对于X的任意一个子集S,设Y中与S相邻的点集为T,满足$|S|\le |T|$。
但是定理里面写的是任意一个子集,而我们想把它转化成区间上的形式,不难想到:在本题中,我们是否可以不枚举所有石子的所有子集,而是只枚举所有的区间是否满足条件呢?答案是肯定的,证明也非常简单:
首先,如果我们取了一个询问,但是没有全取,显然这种情况是不需要讨论的,因为同一个询问中每个石子的邻集都是相同的,如果全取完满足条件的话不全取完也一定满足条件。
其次,如果我们取的询问不是连续的一段区间,这种情况也是没有意义的。因为题中满足询问的r随着l增大而增大,如果我们选的两个的询问段不相交,则我们完全可以分开考虑,看每一段是否满足条件即可。
然后就轻松多啦!我们将询问按位置排序,并剔除掉所有没有用到的堆,设第i个询问我们取了Bi个,那么对于任意$1\le l\le r\le m$,需要满足:
$\sum\limits_{i=l}^r B[i]\le \sum\limits_{i=L[l]}^{R[r]}A[i]$
改成前缀和的形式就是:
$sb[r]-sb[l-1]\le sa[R[r]]-sa[L[l]-1]$
$sb[r]-sa[R[r]]\le sb[l-1]-sa[L[l]-1]$
我们设$C[i]=sb[i]-sa[R[i]],D[i]=sb[i-1]-sa[L[i]-1]$,则限制就变成了
$C[r]\le D[l]$
所以,我们只需要按时间序处理询问,然后在线段树上统计右面C的最大值以及左边D的最小值就能得到当前B的最大值了。然后将i...n的C都+B,i+1...n的D都+B即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=40010;
int X,Y,Z,P;
int n,m;
int L[maxn],R[maxn],A[maxn],B[maxn],ref[maxn],sa[maxn],sb[maxn],p[maxn],C[maxn],D[maxn];
struct node
{
int l,r,org;
}q[maxn];
struct sag
{
int s[maxn<<2],tag[maxn<<2],flag;
inline int MX(int a,int b)
{
if(flag==0) return max(a,b);
else return min(a,b);
}
inline void pushdown(int x)
{
if(tag[x]) s[lson]+=tag[x],s[rson]+=tag[x],tag[lson]+=tag[x],tag[rson]+=tag[x],tag[x]=0;
}
void build(int l,int r,int x)
{
if(l==r)
{
if(flag==0) s[x]=C[l];
else s[x]=D[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
s[x]=MX(s[lson],s[rson]);
}
void updata(int l,int r,int x,int a,int b,int c)
{
if(a<=l&&r<=b)
{
s[x]+=c,tag[x]+=c;
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a,b,c);
if(b>mid) updata(mid+1,r,rson,a,b,c);
s[x]=MX(s[lson],s[rson]);
}
int query(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s[x];
pushdown(x);
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,lson,a,b);
if(a>mid) return query(mid+1,r,rson,a,b);
return MX(query(l,mid,lson,a,b),query(mid+1,r,rson,a,b));
}
}SC,SD;
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
bool cmp(const node &a,const node &b)
{
return a.l<b.l;
}
int main()
{
n=rd();
int i,j;
X=rd(),Y=rd(),Z=rd(),P=rd();
for(i=1;i<=n;i++) A[i]=((i-X)*(i-X)+(i-Y)*(i-Y)+(i-Z)*(i-Z))%P;
m=rd();
if(!m) return 0;
B[1]=rd(),B[2]=rd(),X=rd(),Y=rd(),Z=rd(),P=rd();
for(i=3;i<=m;i++) B[i]=(X*B[i-1]+Y*B[i-2]+Z)%P;
for(i=1;i<=m;i++) q[i].l=rd(),q[i].r=rd(),q[i].org=i;
sort(q+1,q+m+1,cmp);
for(i=1,j=n=0;i<=m;i++)
{
for(j=max(j,q[i].l);j<=q[i].r;j++) A[++n]=A[j],ref[j]=n;
L[q[i].org]=ref[q[i].l],R[q[i].org]=ref[q[i].r],p[q[i].org]=i;
}
for(i=1;i<=n;i++) sa[i]=sa[i-1]+A[i];
for(i=1;i<=m;i++) C[p[i]]=-sa[R[i]],D[p[i]]=-sa[L[i]-1];
SC.flag=0,SD.flag=1,SC.build(1,m,1),SD.build(1,m,1);
for(i=1;i<=m;i++)
{
int rm=SC.query(1,m,1,p[i],m),ln=SD.query(1,m,1,1,p[i]);
B[i]=min(B[i],ln-rm);
printf("%d\n",B[i]);
SC.updata(1,m,1,p[i],m,B[i]);
if(p[i]!=m) SD.updata(1,m,1,p[i]+1,m,B[i]);
}
return 0;
}
【BZOJ2138】stone Hall定理+线段树的更多相关文章
- [BZOJ2138]stone[霍尔定理+线段树]
题意 一共有 \(n\) 堆石子,每堆石子有一个数量 \(a\) ,你要进行 \(m\) 次操作,每次操作你可以在满足前 \(i-1\) 次操作的回答的基础上选择在 \([L_i,R_i]\) 区间中 ...
- [BZOJ2138]stone(Hall定理,线段树)
Description 话说Nan在海边等人,预计还要等上M分钟.为了打发时间,他玩起了石子.Nan搬来了N堆石子,编号为1到N,每堆 包含Ai颗石子.每1分钟,Nan会在编号在\([L_i,R_i] ...
- BZOJ.3693.圆桌会议(Hall定理 线段树)
题目链接 先考虑链.题目相当于求是否存在完备匹配.那么由Hall定理,对于任意一个区间[L,R],都要满足[li,ri]完全在[L,R]中的ai之和sum小于等于总位置数,即R-L+1.(其实用不到H ...
- LOJ.6062.[2017山东一轮集训]Pair(Hall定理 线段树)
题目链接 首先Bi之间的大小关系没用,先对它排序,假设从小到大排 那么每个Ai所能匹配的Bi就是一个B[]的后缀 把一个B[]后缀的匹配看做一条边的覆盖,设Xi为Bi被覆盖的次数 容易想到 对于每个i ...
- loj#6062. 「2017 山东一轮集训 Day2」Pair hall定理+线段树
题意:给出一个长度为 n的数列 a和一个长度为 m 的数列 b,求 a有多少个长度为 m的连续子数列能与 b匹配.两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当 ...
- BZOJ3693: 圆桌会议(Hall定理 线段树)
题意 题目链接 Sol 好的又是神仙题... 我的思路:对于区间分两种情况讨论,一种是完全包含,另一种是部分包含.第一种情况非常好判断,至于计算对于一个区间[l, r]的$\sum a[i]$就可以了 ...
- 模拟赛 怨灵退治 题解(Hall定理+线段树)
题意: 有 n 群怨灵排成一排,燐每秒钟会选择一段区间,消灭至多 k 只怨灵. 如果怨灵数量不足 k,则会消灭尽量多的怨灵. 燐作为一只有特点的猫,它选择的区间是不会相互包含的.它想要知道它每秒最多能 ...
- Codeforces 338E - Optimize!(Hall 定理+线段树)
题面传送门 首先 \(b_i\) 的顺序肯定不会影响匹配,故我们可以直接将 \(b\) 数组从小到大排个序. 我们考虑分析一下什么样的长度为 \(m\) 的数组 \(a_1,a_2,\dots,a_m ...
- BZOJ1135 LYZ(POI2009) Hall定理+线段树
做这个题之前首先要了解判定二分图有没有完备匹配的Hall定理: 那么根据Hell定理,如果任何一个X子集都能连大于等于|S|的Y子集就可以获得完备匹配,那么就是: 题目变成只要不满足上面这个条件就能得 ...
随机推荐
- Xcode不太常见又实用的小技巧
备份, 原文: http://rocry.com/2012/12/17/xcode-tips/ 让代码中的TODO和FIXME变成Warning 选中某个Target > Build Phase ...
- 图解HTTP学习笔记——简单的HTTP协议
简单的HTTP协议 前言 最近在学习Web开发的相关知识,发现<图解HTTP>这本书通俗易懂.所以花时间学习这本书,并记录下学习笔记. 如上图,我们每天都在浏览网页,一般我们都是在浏览器地 ...
- vue如何加入百度联盟广告
在百度联盟代码位管理中创建好对应的代码位之后,点击获取代码,会看到这样一段js 直接复制粘贴到自己网页中便可显示对应广告. 在vue中由于都是vue组件,不支持直接在组件中加入这样一段一段的js代码, ...
- 2. 自动化运维系列之Cobbler给Openstack节点安装操作系统。
preface 我们在一篇博文知道了如何搭建Cobbler,那么下面就通过Cobbler来安抓Openstack所有节点吧. 服务器配置信息如下: 主机名 IP 角色 Cobbler.node.com ...
- Java、C#双语版HttpHelper类(解决网页抓取乱码问题)
在做一些需要抓取网页的项目时,经常性的遇到乱码问题.最省事的做法是去需要抓取的网站看看具体是什么编码,然后采用正确的编码进行解码就OK了,不过总是一个个页面亲自去判断也不是个事儿,尤其是你需要大量抓取 ...
- 实现一个div,左边固定div宽度200px,右边div自适应
实现一个div,左边固定div宽度200px,右边div自适应<div class= "container"> <div class="left&quo ...
- WPF布局管理之Canvas、InkCanvas (转)
一.Canvas 在WPF中子元素的绝对定位的布局控件 其子元素使用Width.Height定义元素的宽度和高度 使用Convas.Left(Convas.Right).Convas.Top(Conv ...
- ios开发之--NSString的操作
NSString的操作,下面记录下他的常用方法: NSString *str = @"1111111111aaaaaaaaa2222222222"; 1.查找 //查找 NSRan ...
- iOS try catch
最近看一些第三方的代码有@try,一副看不懂的样子,真心没用过,于是查了些资料收集在这里,以后遇到就不会再蒙比了.其实这东西确实不怎么用,下文有解释.Objective-C 异常机制 :-- 作用 : ...
- 【AI】face_recognition
1.pip install cmake 2.pip install boost 3.pip install dlib 4.pip install face_recognition