NKOJ 3829 ZZ 的书
问题描述
聪明伶俐、勤奋好学的ZZ 有许多书。
每天上课前,她将她的书一摞一摞地放在书桌上,共n 摞。这n 摞书摆成一列,每摞书
之间的间隔为1cm,第一摞书离桌面边缘的距离为1cm。每节下课后她便会从某一摞书中取出一些书,并将另一些书放入同一摞书中。
如果上一节课的内容很简单,ZZ 便会利用课间的时间在放完书后整理一下她的书,整理
时,ZZ 会选择从L 到R 的一段书,将它们的高度都调整为H。(调整前后书的高度和可能不等)
有一只蚂蚁十分敬佩ZZ 的勤奋刻苦,每次ZZ 拿完书后,它便站在书桌的边缘(靠近第
1 摞数的边缘),想数一数ZZ 到底有多少摞书,但它不可能走完整个书桌,于是它索性每次都待在边缘上的一个固定点,每次只数出它能看见的书。(说明:
已知ZZ每天有m节课,每次ZZ拿书后,蚂蚁按自己的方法都要数一次ZZ的书,但有时候它数不清楚,你需要帮助它数一下当时的书。
输入格式
第一行两个整数N、M。
第二行N个整数Hi,表示各摞数的高度,单位cm(Hi>0)。
接下来M行,每行先有三个整数Xi,Yi,D。表示该课间离边缘Xi cm的那一摞书经过ZZ的调整后,高度变为了Yi cm(1<=Xi,Yi<=n、Yi>0)。
如果D为1,表示ZZ整理了她的书,接下来会有3个整数L,R,H,表示ZZ将L到R的书高度调整为Hcm(1<=L,R<=n,H>0)。如果D为0,表示这个课间ZZ没有整理书。
输出格式
共m行,每行表示第m节课间,ZZ放完和整理完她的书后,蚂蚁数出的本数。
样例输入
输入样例1
3 6
2 1 4
2 5 0
1 2 0
3 6 0
2 1 0
1 1 0
1 2 1 2 3 5
输入样例2
4 4
2 2 3 2
2 4 0
3 7 0
4 1 1 3 4 6
4 8 0
样例输出
输出样例1
2
2
2
1
2
2
输出样例2
1
2
1
1
提示
数据范围
对于30%的数据,1<=n<=5000,1<=m<=8000
对于100%的数据,1<=n<=50000,1<=m<=100000
说明
放书是指改变某一摞的高度
整理是指改变某一段相邻数的高度为同一值
来源 YXV
题解:
1、花一秒看出对于每摞书应该只关心它的斜率(下文只比较斜率)
2、Lazy、区间内最大值、只看该段可以看到的书的数量(维护这个可使查询O(1))
3、维护“只看该段可以看到的书的数量”(以下简称num):
(1)、每个区间的num一定为左区间的num加上右区间受左区间影响后,仍能看到的数量
(2)、所以,需要设计一个cnt函数,返回在区间左侧最高为v时,该区间能被看到的数量:S.num=ls.num+cnt(rs,ls.max);
(3)、对于该区间:
若左儿子的max比v小,则问题转化为求右儿子的贡献
若左儿子的max比v大,则说明右儿子所做贡献不受影响,左儿子所做贡献需重新计算,返回 右儿子的贡献+左儿子重新计算的贡献
#include<cstdio>
#include<iostream>
using namespace std;
const int need=100003;
struct zz
{
int a,b,num,lazy;
double max;
} w[need<<3];
int h[need];
//....................................................................
void putdown(int s)
{
int t=w[s<<1].lazy=w[(s<<1)|1].lazy=w[s].lazy;
w[s].lazy=0;
w[s<<1].num=1,w[(s<<1)|1].num=1;
w[s<<1].max=(double)t/w[s<<1].a,w[(s<<1)|1].max=(double)t/w[(s<<1)|1].a;
}
int cnt(int s,double v)
{
if(w[s].max<=v) return 0;
if(w[s].a==w[s].b) return w[s].max>v ? 1 : 0;
if(w[s].lazy) putdown(s);
if(v>=w[s<<1].max) return cnt((s<<1)|1,v);
else return w[s].num-w[s<<1].num+cnt(s<<1,v);
}
void update(int s)
{
if(w[s].a==w[s].b) return ;
w[s].max=max(w[s<<1].max,w[(s<<1)|1].max);
w[s].num=w[s<<1].num+cnt((s<<1)|1,w[s<<1].max);
}
void build(int l,int r,int s)
{
w[s].a=l,w[s].b=r;
if(l==r)
{
w[s].max=(double)h[l]/l,w[s].num=1;
return ;
}
build(l,(l+r)>>1,s<<1),build((l+r)/2+1,r,(s<<1)|1);
update(s);
}
int x,y,val;
void change(int s)
{
if(x>w[s].b||y<w[s].a) return ;
if(w[s].lazy) putdown(s);
if(x<=w[s].a&&w[s].b<=y)
{
w[s].max=(double)val/w[s].a,w[s].num=1;
if(w[s].a!=w[s].b)w[s].lazy=val;
return ;
}
change(s<<1),change((s<<1)|1);
update(s);
}
//....................................................................
int main()
{
int n,m;scanf("%d%d",&n,&m);
for(int i=1,a;i<=n;i++) scanf("%d",&h[i]);
build(1,n,1);
for(int i=1,a,b,D;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&D);
x=y=a,val=b;
change(1);
if(D==1)
{
scanf("%d%d%d",&x,&y,&val);
change(1);
}
printf("%d\n",w[1].num);
}
}