题目来源
洛谷P1083借教室
https://www.luogu.org/problem/show?pid=1083
思路
线段树存储区间信息(起始位置 结束位置 左儿子指针 右儿子指针 区间最小值 懒标记)
懒标记:当前节点最小值已减去而该节点的儿子节点(如果有的话)还没有减去的值
在线处理 模拟
对于每份订单 在线段树上对区间值进行减法运算
递归深搜寻找需要更新的区间
处理区间时 如果当前不是叶子节点 则下传懒标记(儿子节点区间最小值减去当前节点懒标记 儿子节点懒标记加上当前节点懒标记)
回溯时用儿子节点的区间最小值更新父亲节点的区间最小值
对于一个区间 如果区间最小值小于0 则该订单无法满足 反之 则该订单可以被满足
所以每次处理后 判断根节点区间最小值是否小于0即可
代码(C++)
#include <cstdio>
using namespace std;
int n,m,cnt=0,d,s,t;
struct area
{
int x,y,m,lazy;
area *l,*r;
}p[2000100],*null,*root;
inline area *build(int st,int en);
inline void change(int num,int st,int en,area *pos);
int main()
{
scanf("%d%d",&n,&m);
root=build(1,n);
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&d,&s,&t);
change(d,s,t,root);
if(root->m<0)
{
printf("-1\n%d",i);
return 0;
}
}
printf("0");
return 0;
}
inline void change(int num,int st,int en,area *pos)
{
if(st==pos->x&&en==pos->y)
{
pos->m-=num,pos->lazy+=num;
return ;
}
pos->l->lazy+=pos->lazy;
pos->l->m-=pos->lazy;
pos->r->lazy+=pos->lazy;
pos->r->m-=pos->lazy;
pos->lazy=0;
if(en<=pos->l->y)
{
change(num,st,en,pos->l);
if(pos->l->m<pos->m)
pos->m=pos->l->m;
return ;
}
if(st>=pos->r->x)
{
pos->l->lazy+=pos->lazy;
pos->r->lazy+=pos->lazy;
pos->lazy=0;
change(num,st,en,pos->r);
if(pos->r->m<pos->m)
pos->m=pos->r->m;
return ;
}
pos->l->lazy+=pos->lazy;
pos->r->lazy+=pos->lazy;
pos->lazy=0;
change(num,st,pos->l->y,pos->l);
change(num,pos->r->x,en,pos->r);
if(pos->l->m<pos->m)
pos->m=pos->l->m;
if(pos->r->m<pos->m)
pos->m=pos->r->m;
return ;
}
inline area *build(int st,int en)
{
area *k=&p[++cnt];
k->x=st; k->y=en; k->lazy=0;
if(st==en)
{
k->l=null; k->r=null;
scanf("%d",&k->m);
return k;
}
k->l=build(st,(st+en)/2);
k->r=build((st+en)/2+1,en);
if(k->l->m<=k->r->m)
k->m=k->l->m;
else
k->m=k->r->m;
return k;
}