BZOJ 4592: [Shoi2015]脑洞治疗仪

多写线段树有利于治疗脑洞

0,2操作都好说

操作1需要二分一下能够填脑洞的范围

复杂度m(logn)^2

(rank1怎么跑得辣么快啊,难道有1个Log的做法?)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<ctime>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
#define mmt(a,v) memset(a,v,sizeof(a))
#define tra(i,u) for(int i=head[u];i;i=e[i].next)
using namespace std;
const int N=200000+5;
struct Node{
	int l,r,lx,rx,mx,sum,set;
	int len(){return r-l+1;}
	void work(){
		lx=rx=mx=(set^1)*(r-l+1);
		sum=set*(r-l+1);
	}
}tr[N<<2];
Node operator + (Node l,Node r){
	static Node ans;
	ans.l=l.l;ans.r=r.r;
	ans.sum=l.sum+r.sum;
	if(!l.sum)ans.lx=l.len()+r.lx;
	else ans.lx=l.lx;
	if(!r.sum)ans.rx=r.len()+l.rx;
	else ans.rx=r.rx;
	ans.mx=max(l.rx+r.lx,max(l.mx,r.mx));
	return ans;
}
#define lc o<<1
#define rc o<<1|1
void pushup(int o){
	tr[o].sum=tr[lc].sum+tr[rc].sum;
	if(!tr[lc].sum)tr[o].lx=tr[lc].len()+tr[rc].lx;
	else tr[o].lx=tr[lc].lx;
	if(!tr[rc].sum)tr[o].rx=tr[rc].len()+tr[lc].rx;
	else tr[o].rx=tr[rc].rx;
	tr[o].mx=max(tr[lc].rx+tr[rc].lx,max(tr[lc].mx,tr[rc].mx));
}
void pushdown(int o){
	if(tr[o].set!=-1){
		tr[lc].set=tr[rc].set=tr[o].set;
		tr[lc].work();tr[rc].work();
		tr[o].set=-1;
	}
}
int clear(int o,int a,int b){
	int l=tr[o].l,r=tr[o].r,ans;
	if(l==a&&b==r){
		ans=tr[o].sum;
		tr[o].set=0;
		tr[o].work();
	}else{
		pushdown(o);
		int mid=l+r>>1;
		if(b<=mid)ans=clear(lc,a,b);
		else if(mid<a)ans=clear(rc,a,b);
		else ans=clear(lc,a,mid)+clear(rc,mid+1,b);
		pushup(o);
	}
	return ans;
}
Node query(int o,int a,int b){
	int l=tr[o].l,r=tr[o].r;
	if(l==a&&b==r)return tr[o];
	else{
		pushdown(o);
		int mid=l+r>>1;
		if(b<=mid)return query(lc,a,b);
		else if(mid<a)return query(rc,a,b);
		else return query(lc,a,mid)+query(rc,mid+1,b);
	}
}
void update(int o,int a,int b){
	int l=tr[o].l,r=tr[o].r;
	if(l==a&&b==r)tr[o].set=1,tr[o].work();
	else{
		pushdown(o);
		int mid=l+r>>1;
		if(b<=mid)update(lc,a,b);
		else if(mid<a)update(rc,a,b);
		else update(lc,a,mid),update(rc,mid+1,b);
		pushup(o);
	}
}
int sum(int o,int a,int b){
	int l=tr[o].l,r=tr[o].r;
	if(l==a&&b==r)return r-l+1-tr[o].sum;
	else{
		pushdown(o);
		int mid=l+r>>1;
		if(b<=mid)return sum(lc,a,b);
		else if(mid<a)return sum(rc,a,b);
		else return sum(lc,a,mid)+sum(rc,mid+1,b);
	}
}
void build(int o,int l,int r){
	tr[o].l=l;tr[o].r=r;tr[o].set=-1;tr[o].sum=r-l+1;
	if(l==r)return;
	int mid=l+r>>1;
	build(lc,l,mid);build(rc,mid+1,r);
}
int main(){
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int n,m;scanf("%d%d",&n,&m);
	build(1,1,n);
	while(m--){
		int opt,l,r;
		scanf("%d%d%d",&opt,&l,&r);
		if(!opt)clear(1,l,r);
		else if(opt==2)printf("%d\n",query(1,l,r).mx);
		else{
			int have=clear(1,l,r);
			scanf("%d%d",&l,&r);
			if(!have)continue;
			int st=l;
			while(l<=r){
				int mid=l+r>>1;
				if(sum(1,st,mid)<=have)l=mid+1;
				else r=mid-1;
			}
			update(1,st,l-1);
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值