FJUT 借教室 (线段树区间查询+区间修改)


 

解题思路:看到题目,经典的区间查询+区间修改,我们用线段树维护一段区间的最小值,每当有新的订单,我们就先查询订单时间范围内的最小教室数量,然后与Dj作比较,如果比dj小,那么我们可以标记为false,然后后面的操作都不用看了,因为他只要求输出第一个不满足的订单,否则就按照订单进行区间修改,即在该订单的开始时间和结束时间这个范围内都减少dj个教室。

Code:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1000005;
ll a[N],tree[N<<2],lazy[N<<2];
int n,m;

void pushup(int k) {
	tree[k] = min(tree[k<<1],tree[k<<1|1]);//将父节点更新为较小的值
}

void pushdown(int k) {
	if(lazy[k]) {
		lazy[k<<1] += lazy[k];
		lazy[k<<1|1] += lazy[k];
		
		tree[k<<1] += lazy[k];
		tree[k<<1|1] += lazy[k];
		lazy[k] = 0;
	}
}

void build(int l,int r,int k) {
	if(l == r) {
		tree[k] = a[l];
	}
	else {
		int mid = l + ((r - l) >> 1);
		build(l,mid,k<<1);
		build(mid+1,r,k<<1|1);
		pushup(k);
	}
}

void updata(int L, int R, int v, int l, int r,int k) {
	if(L <= l && r <= R) {
		tree[k] += v;
		lazy[k] += v;
	}
	else {
		pushdown(k);
		int mid = l + ((r - l) >> 1);
		if(L <= mid) {
			updata(L,R,v,l,mid,k<<1);
		}
		if(R > mid) {
			updata(L,R,v,mid+1,r,k<<1|1);
		}
		pushup(k);
	}
}

ll query(int L,int R,int l,int r,int k) {
	if(L <= l && r <= R) {
		return tree[k];
	}
	else {
		pushdown(k);
		ll res = INF;
		int mid = l + ((r - l) >> 1);
		if(L <= mid) {
			res = min(res,query(L,R,l,mid,k<<1));
		}
		if(R > mid) {
			res = min(res,query(L,R,mid+1,r,k<<1|1));
		}
		return res;
	}
}

int main()
{
	int u,v;
	ll w;
//	freopen("X:\Âå¹È²âÊÔÊý¾Ý\P1083_2.in","r",stdin);
	scanf("%d%d",&n,&m);
	memset(lazy,0,sizeof lazy);
	for(int i = 1;i <= n; ++i) {
		scanf("%lld",&a[i]);
	}
	build(1,n,1);
	int fg = 0;//这个标记是否已经不满足条件
	for(int i = 1;i <= m; ++i) {
		scanf("%lld%d%d",&w,&u,&v);
		if(fg)
			continue;
		int k = query(u,v,1,n,1);
		if(k < w) {
			fg = i;
		}
		else {
			updata(u,v,-w,1,n,1);
		}
	}
	if(!fg) {
		puts("0");
	}
	else {
		printf("-1\n%d\n",fg);
	}
	return 0;
}
posted @ 2021-01-17 22:22  MangataTS  阅读(65)  评论(0编辑  收藏  举报