解题思路:看到题目,经典的区间查询+区间修改,我们用线段树维护一段区间的最小值,每当有新的订单,我们就先查询订单时间范围内的最小教室数量,然后与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
%d
",fg);
}
return 0;
}