并不对劲的复健训练-bzoj4592:p4344:[SHOI2015]脑洞治疗仪

题目大意

(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)中,最长一段连续空位有多长。
(n,mleq 2 imes 10^5)

题解

对于第三类操作,可以在线段树的每个点记录该区间靠左端最长连续空位、靠右端最长连续空位、最长连续空位、空位总数,这些信息可以(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])被拆成了(logspace n)个区间,要在每个区间内二分,一次二类操作的总时间是(Theta(log^2space n))
但是(logspace n)个区间中至多有一个是需要二分的,剩下的不是整个区间都被赋值就是整个区间都不被赋值。所以二类操作的时间是(Theta(logspace 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('
');return;}
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('
');
}
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);
}
一些感想

教练追求的“最佳训练方式”只是“让一群人中出现尽可能多的拿奖的人的训练方式”,而每个人追求的“最佳训练方式”是“让自己这一个人更厉害的训练方式”。
所以要么不迷信权威(包括但不限于教练、周围看似很厉害的人、路人),要么指听最权威的“权威”的那句“不迷信权威”。

原文地址:https://www.cnblogs.com/xzyf/p/12664447.html