[SHOI2015]脑洞治疗仪

洛谷题目链接

珂朵莉树吼啊!!!

对于操作$0$,其实就是区间赋值为$0$的操作,直接套模板就行了

对于操作$1$,应该是这个题目最难的操作了(虽然还是很简单),我们先查询$(l_0,r_0)$这个区间的$1$的数量,最后扫一遍$(l_1,r_1)$这个区间,如果$1$的数量够的话直接更改区间值,如果不够的话就把其中够的那块区间赋值就行了,详细看代码

对于操作$2$,直接模板查询就行了

代码:

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#define Set set<Node>::iterator
#define N 200007
using namespace std;
struct Node
{
	int l,r;
	mutable int val;
	Node(int L,int R,int V):l(L),r(R),val(V){}
	Node(int L):l(L){}
	bool operator<(const Node &it)const
	{
		return l<it.l;
	}
};
set<Node> st;
int n,m;
Set Split(int x)
{
	Set it=st.lower_bound(Node(x));
	if(it!=st.end()&&it->l==x)
		return it;
	--it;
	int L=it->l,R=it->r,V=it->val;
	st.erase(it);
	st.insert(Node(L,x-1,V));
	return st.insert(Node(x,R,V)).first;
}
void Change(int l,int r,int v)
{
	Set rr=Split(r+1),ll=Split(l);
	st.erase(ll,rr);
	st.insert(Node(l,r,v));
}
void Hos(int l1,int r1,int l2,int r2)
{
	Set rr=Split(r1+1),ll=Split(l1);
	int cnt=0;
	for(Set it=ll;it!=rr;++it)
		if(it->val)
			cnt+=it->r-it->l+1;
	Change(l1,r1,0);
	rr=Split(r2+1),ll=Split(l2);
	for(Set it=ll;it!=rr;++it)
	{
		if(!cnt)
			break;
		if(!it->val)
		{
			if(cnt>=it->r-it->l+1)
				it->val=1,cnt-=it->r-it->l+1;
			else
				Change(it->l,it->l+cnt-1,1),cnt=0;
		}
	}
}
int Search(int l,int r)
{
	int ans=0,maxn=0;
	Set rr=Split(r+1),ll=Split(l);
	for(Set it=ll;it!=rr;++it)
		if(it->val)
			ans=max(ans,maxn),maxn=0;
		else
			maxn+=it->r-it->l+1;
	ans=max(ans,maxn);
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	st.insert(Node(1,n,1));
	st.insert(Node(n+1));
	for(int i=1;i<=m;++i)
	{
		int opt,l,r,ll,rr;
		scanf("%d%d%d",&opt,&l,&r);
		if(!opt)
			Change(l,r,0);
		if(opt==1)
		{
			scanf("%d%d",&ll,&rr);
			Hos(l,r,ll,rr);
		}
		if(opt==2)
			printf("%d\n",Search(l,r));
	}
	return 0;
}

 

posted @ 2019-01-02 14:49  模拟退火  阅读(133)  评论(0编辑  收藏  举报