【题解】洛谷P2161 会场预约(线段树)

先说一下这道题的解题思路,我们使用离线操作的做法。记录读入的数据,把开始结束日期存在结构体里,并记录是A操作还是B操作。开一个数组记录染色情况、一个cnt数组记录第几个操作推掉了几个预约,读入后我们倒着循环进行查找,如果读入的是B就跳过,如果是A的话就将开始到结束日期的所有点染成当前序号的颜色。如果循环到某段日期它已经有染色标记了,就将当前那段日期所对应的的染色标记的最小值的推掉的预约数+1(因为是倒着来的)(较小的那个标记:明明是我先来的)。最后正着输出答案,如果是A操作就输出当前的cnt,在主函数开一个变量ans记录B操作的答案,并且A操作结束后ans要加上1减去cnt[i](新增了1个预约,推掉了cnt[i]个预约)。

显然 数据范围拒绝我们用暴力的方法解决染色和查找最小值的操作,所以我们只能用线段树。线段树的范围为1到100000,开一个数组minn记录某个结点的minn值,初始化为最大值1e9。先写下放标记和最小值的函数,如果父亲结点的标记为0就不下放,否则就用父亲节点的标记覆盖孩子节点的标记和最小值,父亲节点标记清零。然后是染色的函数,这里在染色的过程中注意更新最小值。再是查找区间最小值的函数,线段树写过

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn=200010;
int mark[maxn*8];
int n;
int ans=0;
struct borrow
{
	int x;
	int y;
}a[maxn];
int b[maxn];
int cnt[maxn];
int minn[maxn*8];
void pushdown(int now,int l,int r)
{
	if(mark[now]==0) return;
	mark[now*2]=mark[now];
	minn[now*2]=mark[now];
	mark[now*2+1]=mark[now];
	minn[now*2+1]=mark[now];
	mark[now]=0;
}
ll getminn(int now,int l,int r,int x,int y)
{
	pushdown(now,l,r);
	if(x<=l&&y>=r)
	{
		return minn[now];
	}
	int mid=(l+r)/2;
	ll ans=1e9;
	if(x<=mid) ans=min(ans,getminn(now*2,l,mid,x,y));
	if(mid+1<=y) ans=min(ans,getminn(now*2+1,mid+1,r,x,y));
	return ans;
}
void addnum(int now,int l,int r,int x,int y,int k)
{
	pushdown(now,l,r);
	//cout<<now<<' '<<l<<' '<<r<<' '<<minn[now]<<endl;
	if(x<=l&&y>=r)
	{
		minn[now]=k;
		mark[now]=k;
		return ;
	}
	if(mark[now]==k)
	{
		return ;
	}
	int mid=(l+r)/2;
	if(x<=mid) addnum(now*2,l,mid,x,y,k);
	if(mid+1<=y) addnum(now*2+1,mid+1,r,x,y,k);
	minn[now]=min(minn[now*2],minn[now*2+1]); 
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=maxn*8;i++)
	{
		minn[i]=1e9;
	}
	for(int i=1;i<=n;i++)
	{
		char c;
		cin>>c;
		if(c=='A')
		{
			b[i]=1; //A
			scanf("%d%d",&a[i].x,&a[i].y);
		}
		if(c=='B')
		{
			b[i]=2; //B
		}
	}
	for(int i=n;i>=1;i--)
	{
		if(b[i]==2) continue;
		else
		{
			ll w=getminn(1,1,100000,a[i].x,a[i].y);
			if(w!=1e9)
			{
				cnt[w]++;
			}
			addnum(1,1,100000,a[i].x,a[i].y,i);
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(b[i]==1)
		{
			cout<<cnt[i]<<endl;
			ans=ans+1-cnt[i];
		}
		else
		{
			cout<<ans<<endl;
		}
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/Rem_Inory/article/details/81286999
今日推荐