P1083 借教室(线段树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/guapi2333/article/details/83386864

其实我第一次做借教室是用线段树做的2333。

显然(额),如果你在分配第i个订单时就gg了,那么往后的订单就都没法分配了。

那么gg的条件是什么?

设数组a[i]表示分配完第j个订单后第i天还有多少个教室供后来的第j个后的订单分配,那么,当a数组中出现a[i]< 0的情况时,表示第i天的教室已经被多个订单分配且无法满足所有的前j个订单。这时就gg了。

所以,我们开一棵线段树维护a数组的最小值,将订单d{}_{j},s{}_{j},t{}_{j}看作为第j个修改操作,将[s{}_{j},t{}_{j}]的所有值减去d{}_{j}。当修改完后min(a{}_{i})小于0,那么当前的订单就gg了,直接输出-1和j即可。若在进行完所有操作后min(a{}_{i})始终\geq 0,则说明所有订单之间互不冲突,输出0即可。

代码:

#include<cstdio>
#include<iostream>
#define ri register int
using namespace std;

const int MAXN=1000020;
int n,q,a[MAXN],d[MAXN],s[MAXN],t[MAXN];
int l[MAXN<<2],r[MAXN<<2],minn[MAXN<<2],tag[MAXN<<2];

inline int read()
{
	int x=0;
	char ch=getchar();
	while(ch<'0'||'9'<ch)	ch=getchar();
	while('0'<=ch&&ch<='9')
	{
		x=(x <<3)+(x <<1)+(ch-'0');
		ch=getchar();
	}
	return x;
}

void pushup(int p)
{
	minn[p]=min(minn[p <<1],minn[p <<1|1]);
}

void pushdown(int p)
{
	minn[p <<1]-=tag[p],tag[p <<1]+=tag[p];
	minn[p <<1|1]-=tag[p],tag[p <<1|1]+=tag[p];
	tag[p]=0;
}

void build(int p,int lft,int rit)
{
	l[p]=lft,r[p]=rit;
	if(l[p]==r[p])
	{
		minn[p]=a[lft];
		return;
	}
	int mid=(lft+rit)>>1;
	build(p <<1,lft,mid);
	build(p <<1|1,mid+1,rit);
	pushup(p);
}

void update(int p,int lft,int rit,int k)
{
	if(lft<=l[p]&&r[p]<=rit)
	{
		minn[p]-=k;tag[p]+=k;
		return;
	}
	pushdown(p);
	if(lft<=r[p <<1])  update(p <<1,lft,rit,k);
	if(l[p <<1|1]<=rit)  update(p <<1|1,lft,rit,k);
	pushup(p);
}

int main()
{
	n=read(),q=read();
	for(ri i=1;i<=n;i++)	a[i]=read();
	build(1,1,n);
	for(ri i=1;i<=q;i++)	d[i]=read(),s[i]=read(),t[i]=read();
	for(ri i=1;i<=q;i++)
	{
		update(1,s[i],t[i],d[i]);
		if(minn[1]<0)  { cout<<"-1"<<'\n'<<i; return 0; }
	}
	cout<<"0";
	return 0;
}

猜你喜欢

转载自blog.csdn.net/guapi2333/article/details/83386864