有$n$个位置,一开始每个位置上都放着一个东西。每个位置上最多放一个东西。 有$m$个操作,分为以下三类: 1.给定$l,r$,将位置$l$到位置$r$的所有东西都拿走并扔掉。 2.给定$l_0,r_0,l_1,r_1$,将位置$l_0$到位置$r_0$的所有东西都拿出来,用来填位置$l_1$到位置$r_1$的空位,优先填编号小的空位。如果拿出来的东西还有剩的就扔掉。 3.给定$l,r$,询问位置$l$到位置$r$中,最长一段连续空位有多长。
对于第三类操作,可以在线段树的每个点记录该区间靠左端最长连续空位、靠右端最长连续空位、最长连续空位、空位总数,这些信息可以$\Theta(1)$合并。 在记录这些信息时,“区间赋值”的标记下传的时间可以是$\Theta(1)$。 第二类操作可以看成给把区间$[l_0,r_0]\(赋值为0,再在\)[l_1,r_1]$中二分一个位置$x$,使$x$尽可能大并且$[l_0,x]\(中的空位数不超过\)[l_0,r_0]\(拿出的东西,再把\)[l_0,x]$赋值为1. 看上去$[l_1,r_1]$被拆成了$log\space n$个区间,要在每个区间内二分,一次二类操作的总时间是$Theta(log^2\space n)$。 但是$log\space n$个区间中至多有一个是需要二分的,剩下的不是整个区间都被赋值就是整个区间都不被赋值。所以二类操作的时间是$\Theta(log\space n)$
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 200007
#define ls (u<<1)
#define rs (u<<1|1)
#define mi ((l+r)>>1)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!=‘-‘)ch=getchar();
if(ch==‘-‘)f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-‘0‘,ch=getchar();
return x*f;
}
void write(int x)
{
char ch[20];int f=0;
if(!x){putchar(‘0‘),putchar(‘\n‘);return;}
if(x<0)putchar(‘-‘),x=-x;
while(x)ch[++f]=x%10+‘0‘,x/=10;
while(f)putchar(ch[f--]);
putchar(‘\n‘);
}
int sum[maxn<<2],lx[maxn<<2],rx[maxn<<2],mx[maxn<<2],mk[maxn<<2],ad,pref;
int n,m;
void pu(int u,int l,int r)
{
sum[u]=sum[ls]+sum[rs];
if(sum[ls]==mi-l+1)lx[u]=(mi-l+1)+lx[rs];
else lx[u]=lx[ls];
if(sum[rs]==r-mi)rx[u]=(r-mi)+rx[ls];
else rx[u]=rx[rs];
mx[u]=max(max(mx[ls],mx[rs]),lx[rs]+rx[ls]);
return;
}
void mark(int u,int l,int r,int k)//k=0,1
{
mk[u]=k;
if(k==0){sum[u]=mx[u]=lx[u]=rx[u]=r-l+1;}
else {sum[u]=mx[u]=lx[u]=rx[u]=0;}
return;
}
void pd(int u,int l,int r){if(mk[u]!=-1)mark(ls,l,mi,mk[u]),mark(rs,mi+1,r,mk[u]),mk[u]=-1;}
int ask(int u,int l,int r,int x,int y)
{
if(x<=l&&r<=y){int tmp=sum[u];mark(u,l,r,0);return r-l+1-tmp;}
pd(u,l,r);int res=0;
if(x<=mi)res+=ask(ls,l,mi,x,y);
if(y>mi)res+=ask(rs,mi+1,r,x,y);pu(u,l,r);
return res;
}
int query(int u,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
{
int res=pref+lx[u];
pref=(sum[u]==r-l+1)?(pref+sum[u]):rx[u];
return max(res,mx[u]);
}
pd(u,l,r);int res=0;
if(x<=mi)res=query(ls,l,mi,x,y);
if(y>mi)res=max(res,query(rs,mi+1,r,x,y));
return res;
}
void work(int u,int l,int r)
{
if(!ad)return;
if(l==r&&ad>sum[u]){ad-=sum[u],mark(u,l,r,1);return;}
if(l==r)return;
pd(u,l,r);
if(ad>=sum[ls])ad-=sum[ls],mark(ls,l,mi,1),work(rs,mi+1,r);
else work(ls,l,mi);
pu(u,l,r);return;
}
void chg(int u,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
{
if(ad)
{
if(ad>=sum[u])ad-=sum[u],mark(u,l,r,1);
else work(u,l,r);
}
return;
}
pd(u,l,r);
if(x<=mi)chg(ls,l,mi,x,y);
if(y>mi)chg(rs,mi+1,r,x,y);
pu(u,l,r);return;
}
int main()
{
n=read(),m=read();
memset(mk,-1,sizeof(mk));
while(m--)
{
int f=read();
if(f==0){int l=read(),r=read(),t=ask(1,1,n,l,r);}
else if(f==1)
{
int l0=read(),r0=read(),l1=read(),r1=read();ad=ask(1,1,n,l0,r0);
chg(1,1,n,l1,r1);
}
else
{
int l=read(),r=read();pref=0;
write(query(1,1,n,l,r));
}
}
return (~(0-0)+1);
}
#####一些感想 教练追求的“最佳训练方式”只是“让一群人中出现尽可能多的拿奖的人的训练方式”,而每个人追求的“最佳训练方式”是“让自己这一个人更厉害的训练方式”。 所以要么不迷信权威(包括但不限于教练、周围看似很厉害的人、路人),要么指听最权威的“权威”的那句“不迷信权威”。
并不对劲的复健训练-bzoj4592:p4344:[SHOI2015]脑洞治疗仪
原文:https://www.cnblogs.com/xzyf/p/12664447.html