【BZOJ2138】stone

Description

话说Nan在海边等人,预计还要等上M分钟。为了打发时间,他玩起了石子。Nan搬来了N堆石子,编号为1到N,每堆包含Ai颗石子。每1分钟,Nan会在编号在[Li,Ri]之间的石堆中挑出任意Ki颗扔向大海(好疼的玩法),如果[Li,Ri]剩下石子不够Ki颗,则取尽量地多。为了保留扔石子的新鲜感,Nan保证任意两个区间[Li,Ri]和[Lj,Rj],不会存在Li<=Lj&Rj<=Ri的情况,即任意两段区间不存在包含关系。可是,如果选择不当,可能无法扔出最多的石子,这时NN就会不高兴了。所以他希望制定一个计划,他告诉你他m分钟打算扔的区间[Li,Ri]以及Ki。现在他想你告诉他,在满足前i-1分钟都取到你回答的颗数的情况下,第i分钟最多能取多少个石子。

Input

第一行正整数N,表示石子的堆数;
第二行正整数x,y,z,P,(1<=x,y,z<=N;P<=500) 
有等式A[i]=[(i-x)^2+(i-y)^2+(i-z)^2] mod P;
第三行正整数M,表示有M分钟;
第四行正整数K[1],K[2],x,y,z,P,(x,y,z<=1000;P<=10000) 
有等式K[i]=(x*K[i-1]+y*K[i-2]+z)mod P。
接下来M行,每行两个正整数L[i],R[i]。
N<=40000   M<=N   1<=L[i]<=R[i]<=N   A[i]<=500

Output

有M行,第i行表示第i分钟最多能取多少石子。

Sample Input

5
3 2 4 7
3
2 5 2 6 4 9
2 4
1 2
3 5

Sample Output

2
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定理+线段树的更多相关文章

  1. [BZOJ2138]stone[霍尔定理+线段树]

    题意 一共有 \(n\) 堆石子,每堆石子有一个数量 \(a\) ,你要进行 \(m\) 次操作,每次操作你可以在满足前 \(i-1\) 次操作的回答的基础上选择在 \([L_i,R_i]\) 区间中 ...

  2. [BZOJ2138]stone(Hall定理,线段树)

    Description 话说Nan在海边等人,预计还要等上M分钟.为了打发时间,他玩起了石子.Nan搬来了N堆石子,编号为1到N,每堆 包含Ai颗石子.每1分钟,Nan会在编号在\([L_i,R_i] ...

  3. BZOJ.3693.圆桌会议(Hall定理 线段树)

    题目链接 先考虑链.题目相当于求是否存在完备匹配.那么由Hall定理,对于任意一个区间[L,R],都要满足[li,ri]完全在[L,R]中的ai之和sum小于等于总位置数,即R-L+1.(其实用不到H ...

  4. LOJ.6062.[2017山东一轮集训]Pair(Hall定理 线段树)

    题目链接 首先Bi之间的大小关系没用,先对它排序,假设从小到大排 那么每个Ai所能匹配的Bi就是一个B[]的后缀 把一个B[]后缀的匹配看做一条边的覆盖,设Xi为Bi被覆盖的次数 容易想到 对于每个i ...

  5. loj#6062. 「2017 山东一轮集训 Day2」Pair hall定理+线段树

    题意:给出一个长度为 n的数列 a和一个长度为 m 的数列 b,求 a有多少个长度为 m的连续子数列能与 b匹配.两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当 ...

  6. BZOJ3693: 圆桌会议(Hall定理 线段树)

    题意 题目链接 Sol 好的又是神仙题... 我的思路:对于区间分两种情况讨论,一种是完全包含,另一种是部分包含.第一种情况非常好判断,至于计算对于一个区间[l, r]的$\sum a[i]$就可以了 ...

  7. 模拟赛 怨灵退治 题解(Hall定理+线段树)

    题意: 有 n 群怨灵排成一排,燐每秒钟会选择一段区间,消灭至多 k 只怨灵. 如果怨灵数量不足 k,则会消灭尽量多的怨灵. 燐作为一只有特点的猫,它选择的区间是不会相互包含的.它想要知道它每秒最多能 ...

  8. Codeforces 338E - Optimize!(Hall 定理+线段树)

    题面传送门 首先 \(b_i\) 的顺序肯定不会影响匹配,故我们可以直接将 \(b\) 数组从小到大排个序. 我们考虑分析一下什么样的长度为 \(m\) 的数组 \(a_1,a_2,\dots,a_m ...

  9. BZOJ1135 LYZ(POI2009) Hall定理+线段树

    做这个题之前首先要了解判定二分图有没有完备匹配的Hall定理: 那么根据Hell定理,如果任何一个X子集都能连大于等于|S|的Y子集就可以获得完备匹配,那么就是: 题目变成只要不满足上面这个条件就能得 ...

随机推荐

  1. mint-ui loadmore组件注意问题

    loadTop(){ this.$store.dispatch('getNewsList',{channelId:this.id,page:0,size:this.size}); this.$refs ...

  2. js准确获取当前页面url网址信息

    这篇文章主要为大家介绍了js准确获取当前页面url网址信息的多种方法,包括正则法.split拆分法等,需要的朋友可以参考下   在WEB开发中,时常会用到javascript来获取当前页面的url网址 ...

  3. 表达式树(Expression Tree)

    你每创建一个表示表达式的实例时,都可以将该类型实例看成是一棵表达式树.每种表示表达式的类型都有一个具体的类型,如Expression的Variable()方法创建的是ParameterExpressi ...

  4. Ubuntu中的“资源管理器”System Monitor

    我们在Windows中经常要查看“资源管理器”来了解系统运行情况,对进程进行操作等等... 在Windows桌面任务栏右键“启动任务管理器”: 学习Linux,自然也希望有类似的“资源管理器”,安装完 ...

  5. MySQL 字符串拼接详解

    在Mysql 数据库中存在两种字符串连接操作.具体操作如下一. 语法:   1. CONCAT(string1,string2,…)   说明 : string1,string2代表字符串,conca ...

  6. VS2017 Pro未能找到路径“……\bin\roslyn\csc.exe”的解决方案

    VS2017改用roslyn编译的,新的roslyn编译器,支持c# 6.0语法.它放到bin里面去是为了支持asp.net应用的动态编译. 它是通过nuget的包Microsoft.CodeDom. ...

  7. orcle时间

    Oracle计算时间差函数 两个Date类型字段:START_DATE,END_DATE,计算这两个日期的时间差 (分别以天,小时,分钟,秒,毫秒): 天: ROUND(TO_NUMBER(END_D ...

  8. Java查看类的成员

    在一个类的内部,一般包括以下几类成员:成员变量.构造方法.普通方法和内部类等.使用反射机制可以在无法查看源代码的情况下查看类的成员.编写程序,使用反射机制查看ArrayList类中定义的成员变量.构造 ...

  9. Java通过复选框控件数组实现添加多个复选框控件

    编写程序,通过复选框控件数组事先选择用户爱好信息的复选框,在该程序中,要求界面中的复选框数量可以根据指定复选框名称的字符串数组的长度来自动调节. 思路如下: 创建JPanel面板对象: 使用JPane ...

  10. HybridApp启动引导页的实现

    有一种帅叫做长话短说,@孙红雷,--这可以叫做“短帅”吗,^_^ 首先说下思路,既然是Hybrid APP, 那就是可以用html的方式实现,启动引导页比较常见的展示方式是滑动,那么我们就可以使用图片 ...