正解:线段树+二分答案/分块

解题报告:

懒得写题目描述辣,放个传送门qwq

首先线段树是很容易想到的?区间修改嘛

然后,操作1就是模板嘛,有一定难度的在于操作2和3(其实是012,不管,强行做123x

那操作23怎么实现呢?

二分

还是有点难度的对我来说,所以都说下趴$QAQ$

    • 首先操作2,我们可以先分别求下用来填充的区间和被填充的区间的1的数量,如果用来填充的1的数量>我们要填充的那块儿的总数-被填充的1的数量(也就是要填的0的数量嘛$quq$,那我们就可以直接填上去,和直接的区间修改没有差别

 那如果小于怎么搞?

 二分

 好滴讲完了,完

 实在懒得讲下去了,,,但是觉得$gql$这么蠢再看一遍不一定能理解啊,,,还是再港下?

 就从前往后找1,二分地搞,然后找到1的那段都可以跳过,于是就一直加一直加一直加,最后就好了

    • 关于操作3,类似,只是会变成取max,同样是二分找到一直为0的一段区间嘛,然后就完?

大概能懂趴?

然后,我发现我脑子不太好,,,我不知道为啥突然脑子一抽就觉得,我好像这题没写题解?于是就又写了篇,,,于是我就把那篇删了,然后因为表述有点儿不一样所以还是把那篇的表述搬过来好了$qwq$

首先建棵线段树,存这段区间内所有1的个数

港最简单的操作,就是那个0$lr$.相当于就$lr$都变成0,没什么可说的嗷,基本操作$qwq$

然后1和2的操作想法都是类似的,分别港下趴还是qwq

首先对于操作$1\ l_{0}\ r_{0}\ l_{1}\ r_{1}$,$l_{0}$到$r_{0}$肯定可以直接赋值0了不解释

首先如果$l_{0}$到$r_{0}$中1的数量是大于$l_{0}$到$r_{0}$中0的数量就直接让$l_{1}$到$r_{1}$赋值为1就成了,不需要别的操作了,依然基本操作呢

但是如果小于,思考怎么做

肯定是从前往后跑能补就补就是了,那怎么看能不能补呢,首先我们肯定要先定位到第一个是0的点

这个可以用$query$直接求下判断是否是1,然后如果是1就二分查找找到第一个是0的点(关于二分的这个之后会另外讲实现的$qwq$)

然后继续用二分找到第一个不是0的点,那么中间这一段就都是0

然后判断,如果这一段的0的长度大于可以补的长度了,直接把能补的长度那段赋值成1,然后就补不上了退出

然后如果小于等于,就可以继续补,就把这一段赋值成1继续补重复之间的步骤就成

然后操作1就讲完了,还是比较好理解的呢?

然后是$2\ l\ r$,这个一样是用的二分(听说还有种神仙方法线段树存的是最长0序列长度?这个怎么操作?$mk$下,会学习落实的$qwq$)

差不多套路,首先判断是不是1如果是1让它跳到0去

然后二分查找找出这一段0的长度,然后$ans$取长度$max$就成

最后说下这个二分,就可以结束啦!

首先明确下,$mid$指这一段中连续的0/1(函数中用$k$表示)的长度

然后$query$查找,查这一段的和是多少,如果和=$k\cdot $这段长度,说明这是一段连续长度,说明能继续延伸,就$l=mid+1$

否则不能的话就$r=mid-1$咯

然后注意一下线段树存最长做法和珂朵莉做法还没落实鸭$QAQ$

然后这题我$WA$了半天,一直就是80,90,95的$QAQ$,改到崩溃,一直没想明白为啥$QAQ$

先来贴下提交记录:

在超时边缘疯狂徘徊:)然后我还一直以为是死循环,改了好多遍,然后顺手吸了个氧然后就过来,然后我才知道,我是,人丑常数大,超时了,,,哭了

然后我搞了下把ll全改成int就过去辽

气死:)

我记住ll了我这辈子也不会用ll了x

然后代码在此:

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define rp(i,x,y) for(register ll i=x;i<=y;++i)
#define lc(x) x<<1
#define rc(x) (x<<1)|1
#define md(x,y) (x+y)>>1 const ll N=+;
ll n,m,tr[N<<],add[N<<],trtr[N<<]; inline ll read()
{
char ch=getchar();ll x=;bool y=;
while(ch!='-' && (ch<'' || ch>''))ch=getchar();
if(ch=='-')y=,ch=getchar();
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=getchar();
return y?x:-x;
}
inline void pushdown(ll d,ll l,ll r,ll mid)
{
if(add[d]!=)
{
--add[d];
tr[lc(d)]=add[d]*(mid-l+);tr[rc(d)]=add[d]*(r-mid);
add[lc(d)]=add[d]+;add[rc(d)]=add[d]+;
add[d]=;
}
}
void update(ll d,ll l,ll r,ll x,ll y,ll k)
{
if(l>y || x>r)return;
if(l>=x && r<=y){tr[d]=(r-l+)*k;add[d]=k+;return;}
ll mid=md(l,r);pushdown(d,l,r,mid);
if(x<=mid)update(lc(d),l,mid,x,y,k); if(mid<y)update(rc(d),mid+,r,x,y,k);
tr[d]=tr[lc(d)]+tr[rc(d)];
}
void build(ll d,ll l,ll r)
{
if(l==r){tr[d]=;return;}
ll mid=md(l,r);
build(lc(d),l,mid);build(rc(d),mid+,r);
tr[d]=tr[lc(d)]+tr[rc(d)];
}
ll query(ll d,ll l,ll r,ll x,ll y)
{
if(l>y||x>r)return ;if(x<=l&&r<=y)return tr[d];
ll mid=md(l,r),ret=;
pushdown(d,l,r,mid);
if(mid>=x)ret+=query(lc(d),l,mid,x,y); if(mid<y)ret+=query(rc(d),mid+,r,x,y);
return ret;
}
inline ll efcz(ll x,ll y,ll k)
{
if (x>y) return -;
ll l=,r=y-x,mid;
while (l<=r)
{
mid=md(l,r);
if(query(,,n,x,x+mid)==k*(mid+))l=mid+;
else r=mid-;
}
return l;
}
inline void work1(){ll t1=read(),t2=read();update(,,n,t1,t2,);return;}
inline void work2()
{
ll t1=read(),t2=read(),t3=read(),t4=read();
int num=query(,,n,t1,t2),p=;
update(,,n,t1,t2,);
if (num>=t4-t3+-query(,,n,t3,t4))update(,,n,t3,t4,);
else
{
if(num!=)
{
while()
{
if (query(,,n,t3,t3)==){p=efcz(t3,t4,);t3+=p;}
p=efcz(t3,t4,);
if(p==-)break;
if (p>num){update(,,n,t3,t3+num-,);break;}
update(,,n,t3,t3+p-,);num-=p;t3+=p;
}
}
}
}
inline void work3()
{
ll t1=read(),t2=read();
ll ans=,p=;
while()
{
if (query(,,n,t1,t1)==){p=efcz(t1,t2,);t1+=p;}
p=efcz(t1,t2,);
if(p==-)break;
ans=max(ans,p);t1+=p;
if(t1>t2)break;
}
printf("%lld\n",ans);
} int main()
{
n=read();m=read();build(,,n);
while(m--){ll t=read();if(t==)work1();if(t==)work2();if(t==)work3();}
return ;
}

over

昂还有就我认真思考了下发现,分块应该是可以做的?

$umm$然后就尝试用分块写了一发

$vjudge$上过了,然后洛谷上T了

(...什么鬼啊我线段树$vjudge\ T$洛谷过,然后分块$vjudge$过洛谷$T$10个点嘤嘤嘤

嗷然后我吸氧过去了,先这样趴$QAQ$

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rp(i,x,y) for(register int i=x;i<=y;++i)
#define my(i,x,y) for(register int i=x;i>=y;--i) const ll N=+;
int n,m,len,sum,ans,l,r,t,a[N],block[N],siz[N],cnt[N],ml[N],mr[N],bl[N],br[N],b[N],mx[N]; inline int read()
{
char ch=getchar();int x=;bool y=;
while(ch!='-' && (ch<'' || ch>''))ch=getchar();
if(ch=='-')ch=getchar(),y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=getchar();
return y?x:-x;
}
inline void move(ll l,ll r){rp(i,l,r){if(sum==)return;if(a[i]==)a[i]=,--sum;}}
inline void clr(ll l,ll r){rp(i,l,r)a[i]=;}
inline void add(ll l,ll r){rp(i,l,r)a[i]=;}
inline void full(ll x){b[x]=;mx[x]=ml[x]=mr[x]=;cnt[x]=siz[x];}
inline void empt(ll x){b[x]=;mx[x]=ml[x]=mr[x]=siz[x];cnt[x]=;}
inline void pushdown(int x)
{
if(b[x]==)clr(bl[x],br[x]);
if(b[x]==)add(bl[x],br[x]);
b[x]=;
}
inline void recount(int x)
{
cnt[x]=;int tmp=;mx[x]=;ml[x]=siz[x];mr[x]=siz[x];
rp(i,bl[x],br[x])
{
if(a[i]==)++tmp;else tmp=;
mx[x]=max(mx[x],tmp);cnt[x]+=a[i];
}
rp(i,bl[x],br[x])if(a[i]==){ml[x]=i-bl[x];break;}
my(i,br[x],bl[x])if(a[i]==){mr[x]=br[x]-i;return;}
}
inline void work1()
{
l=read();r=read();
if(block[r]-block[l]<){pushdown(block[l]);pushdown(block[r]);clr(l,r);recount(block[l]);recount(block[r]);return;}
rp(i,block[l]+,block[r]-){b[i]=;mx[i]=ml[i]=mr[i]=siz[i];cnt[i]=;}
pushdown(block[l]);pushdown(block[r]);
clr(l,br[block[l]]);clr(bl[block[r]],r);
recount(block[l]);recount(block[r]);
}
inline void work2()
{
l=read();r=read();sum=;
if(block[r]-block[l]<)
{
pushdown(block[l]);pushdown(block[r]);
rp(i,l,r)if(a[i]==)++sum;clr(l,r);
recount(block[l]);recount(block[r]);
return;
}
rp(i,block[l]+,block[r]-){sum+=cnt[i];empt(i);}
pushdown(block[l]);pushdown(block[r]);
rp(i,l,br[block[l]])if(a[i]==)++sum;rp(i,bl[block[r]],r)if(a[i]==)++sum;
clr(l,br[block[l]]);clr(bl[block[r]],r);
recount(block[l]);recount(block[r]);
}
inline void work3()
{
l=read();r=read();
if(block[r]-block[l]<)
{
pushdown(block[l]);pushdown(block[r]);
move(l,r);
recount(block[l]);recount(block[r]);
return;
}
pushdown(block[l]);move(l,br[block[l]]);recount(block[l]);if(sum==)return;
rp(i,block[l]+,block[r]-)
{
if(siz[i]-cnt[i]>sum){pushdown(i);move(bl[i],br[i]);recount(i);return;}
else{sum-=(siz[i]-cnt[i]);full(i);}
if(sum==)return;
}
pushdown(block[r]);move(bl[block[r]],r);recount(block[r]);
}
inline void work4()
{
l=read();r=read();
ans=sum=;
if(block[r]-block[l]<)
{
pushdown(block[l]);pushdown(block[r]);
rp(i,l,r){if(a[i]==)++sum;else sum=;ans=max(sum,ans);}
printf("%d\n",ans);
return;
}
pushdown(block[l]);
rp(i,l,br[block[l]]){if(a[i]==)sum++;else sum=;ans=max(sum,ans);}
rp(i,block[l]+,block[r]-)
{
sum=sum+ml[i];ans=max(ans,max(sum,mx[i]));
if(siz[i]!=ml[i])sum=mr[i],ans=max(ans,sum);
}
pushdown(block[r]);rp(i,bl[block[r]],r){if(a[i]==)sum++;else sum=;ans=max(sum,ans);}
printf("%d\n",ans);
} int main()
{
n=read();m=read();
len=sqrt(n);
for(int i=;i<=n;i++)
{
a[i]=;
block[i]=(i-)/len+;++siz[block[i]];++cnt[block[i]];
if(!bl[block[i]])bl[block[i]]=i;br[block[i]]=i;
}
for(int i=;i<=m;i++)
{
t=read();
if(t==){work1();continue;}
if(t==){work2();work3();continue;}
work4();
}
return ;
}

洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块的更多相关文章

  1. 洛谷$P2824\ [HEOI2016/TJOI2016]$ 排序 线段树+二分

    正解:线段树+二分 解题报告: 传送门$QwQ$ 昂着题好神噢我$jio$得$QwQQQQQ$,,, 开始看到长得很像之前考试题的亚子,,,然后仔细康康发现不一样昂$kk$,就这里范围是$[1,n]$ ...

  2. 洛谷 P3373 【模板】线段树 2

    洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...

  3. [BZOJ 2653] middle(可持久化线段树+二分答案)

    [BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...

  4. 洛谷P4891 序列(势能线段树)

    洛谷题目传送门 闲话 考场上一眼看出这是个毒瘤线段树准备杠题,发现实在太难调了,被各路神犇虐哭qwq 考后看到各种优雅的暴力AC......宝宝心里苦qwq 思路分析 题面里面是一堆乱七八糟的限制和性 ...

  5. BZOJ4592 SHOI2015脑洞治疗仪(线段树)

    考虑需要资瓷哪些操作:区间赋值为0:统计区间1的个数:将区间前k个0变为1:询问区间最长全0子串.于是线段树维护区间1的个数.0的个数.最长前缀后缀全0子串即可.稍微困难的是用一个log实现将区间前k ...

  6. 洛谷P3372 【模板】线段树 1

    P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷 ...

  7. 洛谷 P2574 XOR的艺术(线段树 区间异或 区间求和)

    To 洛谷.2574 XOR的艺术 题目描述 AKN觉得第一题太水了,不屑于写第一题,所以他又玩起了新的游戏.在游戏中,他发现,这个游戏的伤害计算有一个规律,规律如下 1. 拥有一个伤害串为长度为n的 ...

  8. Bzoj5294/洛谷P4428 [Bjoi2018]二进制(线段树)

    题面 Bzoj 洛谷 题解 考虑一个什么样的区间满足重组之后可以变成\(3\)的倍数.不妨设\(tot\)为一个区间内\(1\)的个数.如果\(tot\)是个偶数,则这个区间一定是\(3\)的倍数,接 ...

  9. 【题解】洛谷P1198 [JSOI2008] 最大数(线段树)

    洛谷P1198:https://www.luogu.org/problemnew/show/P1198 思路 一道水水的线段树 20分钟A掉 这道题只涉及到单点修改和区间查询 所以这道题甚至不用Laz ...

随机推荐

  1. Robot Framework配置发送邮件功能

    请参考:http://www.robotframework.net/?/article/118

  2. Ubuntu 13.10 下安装搜狗输入法

    1.卸载ibus输入法: sudo apt-get remove ibus     sudo为取得root权限的意思,Ubuntu系统默认root账户关闭,很多操作需要取得root     权限才可以 ...

  3. 计算直线与WGS84椭球的交点

    /************************************************************************/ /*线段与WGS84椭球求交 x^2/a^2+y^ ...

  4. ScrollView 定位

    1.固定到顶部scroll_view.requestFocusFromTouch();scroll_view.setScrollX(0); 2.固定到指定位置 int[] location = new ...

  5. Suggestion: add 'tools:replace="android:value"' to <meta-data> element at AndroidManifest.xml:25:5-27:41 to override.

    记录下来少走些坑吧 一:不管用 tools:replace="android:icon,android:theme" xmlns:tools="http://schema ...

  6. 禁用Visual Studio 2013的Browser Link功能 -调试不断请求http://localhost:6154/c4ad1c693ebf428283832eaa827f9c6e/arterySignalR/poll?transport=longPolling...

    关于禁用查到的解决: 作者:donny945 https://my.oschina.net/ind/blog/359003 今天浏览器调试代码的时候,一直出现以下的请求,导致需要看的请求都被淹没了,之 ...

  7. linux进程永久放后台运行

    我们使用ssh连接服务器之后,如果在执行某个命令需要时间特别长,当把终端断掉之后,命令就自动停止了一般我们在ssh客户端执行命令之后,默认他的父进程是ssh,所以把ssh终端关掉之后,子进程也就被自动 ...

  8. Puppet nginx+passenger模式配置

    Puppet nginx+passenger模式配置 一.简述:Puppet 运行在单台服务器上默认启动的是一个puppetmaster进程,当遇到client高并发的请求时,基于ruby的WEBRi ...

  9. Linux设备驱动剖析之SPI(四)

    781行之前没什么好说的,直接看783行,将work投入到工作队列里,然后就返回,在这里就可以回答之前为什么是异步的问题.以后在某个合适的时间里CPU会执行这个work指定的函数,这里是s3c64xx ...

  10. 【面试题】Python高级开发工程师面试题

    线上面试题,有空整理答案,欢迎大家回复答案