[CSP-S模拟测试]:甜圈(线段树)

题目描述

  $D$先生,是一个了不起的甜甜圈制造商。今天,他的厨房准备在日出之前制作甜甜圈。$D$先生瞬间完成了$N$个油炸圈饼。但是,这些油炸圈饼得先经过各种装饰任务才可以成为甜甜圈销售:填充奶油,浸入巧克力,打顶可爱,丰富多彩的东西等等。
  装饰任务有$K$个,任务编号为$1$到$K$,并且每一个甜甜圈都必须严格按照$K$个任务以$1,2,...,K$的顺序仅完成一次,才能成为销售物品。
  $D$先生将$N$个甜甜圈排成一列,他似乎打算一次完成每个装饰任务。但是,昨天晚上熬夜的$D$先生每个任务只装饰了部分连续区间的甜甜圈。这显然是一个错误!不仅如此,他还可能是做了几次同一任务,任务的顺序也是混乱的。
  没有经过正确流程装饰的甜甜圈不能作为销售物品提供,所以他应该把它们丢掉。幸运的是,有数据依次记录了他所做的一系列任务。数据包含以下信息:对于每个任务,装饰的甜甜圈的连续区间$[l,r]$和任务的$ID\ x$。
  请编写一个程序,列举可在展示柜中显示的甜甜圈的数量,作为销售给定记录数据的答案。


输入格式

第一行两个整数$N$和$K$,表示有$N$个甜甜圈和$K$个任务。
第二行一个整数$T$,表示$D$先生依次完成了$T$个区间的装饰。
接下来$T$行,每行三个正整数$l_i,r_i,x_i$,分别表示区间$[l_i,r_i]$的甜甜圈完成了$ID$为$x_i$的装饰任务。


输出格式

一个整数,表示能作为展示的甜甜圈的数量。


样例

样例输入:

5 3
5
2 3 1
1 3 2
4 5 1
2 4 3
3 5 2

样例输出:

1


数据范围与提示

样例解释:

$1$号甜甜圈没有完成任务$1$就完成了任务$2$所以抛弃,$3$号甜甜圈的任务$2$被重复完成了$2$次,抛弃!$4$号甜甜圈先完成了任务$3$再完成任务$2$,抛弃!$5$号甜甜圈没有完成任务$3$,抛弃!所以只有$2$可以展示。

数据范围:

对于$40\%$的数据,$N,K,T\leqslant 5,000$
对于另外$20\%$的数据,$K\leqslant 100$
对于另外$10\%$的数据,$l_i=r_i$
对于$100\%$的数据,$1\leqslant N,K,T\leqslant 200,000,x_i\leqslant K,1\leqslant l_i\leqslant r_i\leqslant N$


题解

显然是一道线段树,我们考虑如何维护。

用两个懒标记,分别表示其上端点和下端点,$-1$表示没有懒标记,$-2$表示这段区间已经不合法即可。

最后将整棵树跑一边即可统计答案。

时间复杂度:$\Theta(N\log N+T\log N)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
int N,K,T;
int tr[1000000],lz1[1000000],lz2[1000000];
int ans;
void build(int x,int l,int r)
{
	lz1[x]=lz2[x]=-2;
	if(l==r)return;
	int mid=(l+r)>>1;
	build(L(x),l,mid);
	build(R(x),mid+1,r);
}
void pushdown(int x)
{
	if(lz1[x]==-2)return;
	if(lz1[x]==-1)
	{
		tr[L(x)]=tr[R(x)]=lz1[L(x)]=lz1[R(x)]=lz2[L(x)]=lz2[R(x)]=-1;
		return;
	}
	if(tr[L(x)]!=-1)
	{
		if(tr[L(x)]+1==lz1[x])tr[L(x)]=lz2[x];
		else tr[L(x)]=-1;
	}
	if(tr[R(x)]!=-1)
	{
		if(tr[R(x)]+1==lz1[x])tr[R(x)]=lz2[x];
		else tr[R(x)]=-1;
	}
	if(lz1[L(x)]!=-1)
	{
		if(lz1[L(x)]==-2){lz1[L(x)]=lz1[x];lz2[L(x)]=lz2[x];}
		else if(lz2[L(x)]+1==lz1[x])lz2[L(x)]=lz2[x];
		else lz1[L(x)]=lz2[L(x)]=-1;
	}
	if(lz1[R(x)]!=-1)
	{
		if(lz1[R(x)]==-2){lz1[R(x)]=lz1[x];lz2[R(x)]=lz2[x];}
		else if(lz2[R(x)]+1==lz1[x])lz2[R(x)]=lz2[x];
		else lz1[R(x)]=lz2[R(x)]=-1;
	}
	lz1[x]=lz2[x]=-2;
}
void change(int x,int l,int r,int L,int R,int w)
{
	if(r<L||R<l)return;
	if(L<=l&&r<=R)
	{
		if(tr[x]!=-1)
		{
			if(tr[x]+1==w)tr[x]++;
			else tr[x]=-1;
		}
		if(lz1[x]!=-1)
		{
			if(lz1[x]==-2)lz1[x]=lz2[x]=w;
			else if(lz2[x]+1==w)lz2[x]++;
			else lz1[x]=lz2[x]=-1;
		}
		return;
	}
	pushdown(x);
	int mid=(l+r)>>1;
	change(L(x),l,mid,L,R,w);
	change(R(x),mid+1,r,L,R,w);
}
void ask(int x,int l,int r)
{
	if(l==r)
	{
		if(tr[x]==K)ans++;
		return;
	}
	pushdown(x);
	int mid=(l+r)>>1;
	ask(L(x),l,mid);
	ask(R(x),mid+1,r);
}
int main()
{
	scanf("%d%d%d",&N,&K,&T);
	build(1,1,N);
	while(T--)
	{
		int l,r,x;
		scanf("%d%d%d",&l,&r,&x);
		change(1,1,N,l,r,x);
	}
	ask(1,1,N);
	printf("%d",ans);
	return 0;
}

rp++

posted @ 2019-10-06 21:43  HEOI-动动  阅读(258)  评论(0编辑  收藏  举报