正解:线段树+二分/珂朵莉树
解题报告:
先放个传送门qwq(啊发现好多题解都忘了放传送门呢QAQ有时间一起补上QAQ
然后大概说下思路,其实比较好想只是实现有点儿复杂呢?
大概就是个线段树+二分鸭
首先建棵线段树,存这段区间内所有1的个数
港最简单的操作,就是那个0lr.相当于就lr都变成0,没什么可说的嗷,基本操作qwq
然后1和2的操作想法都是类似的,分别港下趴还是qwq
首先1l0r0l1r1,肯定可以直接赋值0了不解释
首先如果l0r0中1的数量是大于l0r0中0的数量就直接让l1r1赋值为1就成了不需要别的操作了,依然基本操作呢
但是如果小于,思考怎么做
肯定是从前往后跑能补就补就是了,那怎么看能不能补呢,首先我们肯定要先定位到第一个是0的点
这个可以用query直接求下判断是否是1,然后如果是1就二分查找找到第一个是0的点(关于二分的这个之后会另外讲实现的qwq)
然后继续用二分找到第一个不是0的点,那么中间这一段就都是0
然后判断,如果这一段的0的长度大于可以补的长度了,直接把能补的长度那段赋值成1,然后就补不上了退出
然后如果小于等于,就可以继续补,就把这一段赋值成1继续补重复之间的步骤就成
然后操作1就讲完了,还是比较好理解的呢?
然后是2lr,这个一样是用的二分(听说,还有种神仙方法线段树存的是最长0序列长度?这个怎么操作?mk下会学习落实的qwq)
差不多套路,首先判断是不是1如果是1让它跳到0去
然后二分查找找出这一段0的长度,然后ans取长度max就成
最后说下这个二分,就可以结束啦!
首先明确mid指这一段中连续的0/1(函数中用k表示)的长度
然后query查找,查这一段的和是多少,如果和=k*这段长度,说明这是一段连续长度,说明能继续延伸,就l=mid+1
否则不能的话就r=mid-1咯
然后就完美结束啦?那这道题就还有俩坑没填,一个是线段树存最长做法,一个是珂朵莉做法
没啦!
#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=200000+10; ll n,m,tr[N<<2],add[N<<2],trtr[N<<2]; inline ll read() { char ch=getchar();ll x=0;bool y=1; while(ch!='-' && (ch<'0' || ch>'9'))ch=getchar(); if(ch=='-')y=0,ch=getchar(); while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar(); return y?x:-x; } inline void pushdown(ll d,ll l,ll r,ll mid) { if(add[d]!=0) { --add[d]; tr[lc(d)]=add[d]*(mid-l+1);tr[rc(d)]=add[d]*(r-mid); add[lc(d)]=add[d]+1;add[rc(d)]=add[d]+1; add[d]=0; } } 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+1)*k;add[d]=k+1;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+1,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]=1;return;} ll mid=md(l,r); build(lc(d),l,mid);build(rc(d),mid+1,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 0;if(x<=l&&r<=y)return tr[d]; ll mid=md(l,r),ret=0; pushdown(d,l,r,mid); if(mid>=x)ret+=query(lc(d),l,mid,x,y); if(mid<y)ret+=query(rc(d),mid+1,r,x,y); return ret; } inline ll efcz(ll x,ll y,ll k) { if (x>y) return -1; ll l=0,r=y-x,mid; while (l<=r) { mid=md(l,r); if(query(1,1,n,x,x+mid)==k*(mid+1))l=mid+1; else r=mid-1; } return l; } inline void work1(){ll t1=read(),t2=read();update(1,1,n,t1,t2,0);return;} inline void work2() { ll t1=read(),t2=read(),t3=read(),t4=read(); int num=query(1,1,n,t1,t2),p=0; update(1,1,n,t1,t2,0); if (num>=t4-t3+1-query(1,1,n,t3,t4))update(1,1,n,t3,t4,1); else { if(num!=0) { while(1) { if (query(1,1,n,t3,t3)==1){p=efcz(t3,t4,1);t3+=p;} p=efcz(t3,t4,0); if(p==-1)break; if (p>num){update(1,1,n,t3,t3+num-1,1);break;} update(1,1,n,t3,t3+p-1,1);num-=p;t3+=p; } } } } inline void work3() { ll t1=read(),t2=read(); ll ans=0,p=0; while(1) { if (query(1,1,n,t1,t1)==1){p=efcz(t1,t2,1);t1+=p;} p=efcz(t1,t2,0); if(p==-1)break; ans=max(ans,p);t1+=p; if(t1>t2)break; } printf("%lld\n",ans); } int main() { n=read();m=read();build(1,1,n); while(m--){ll t=read();if(t==0)work1();if(t==1)work2();if(t==2)work3();} return 0; }