noip 2012 提高组 Day2 T2 LuoguP1083 借教室

题面

在这里插入图片描述

分析

由于本题涉及区间,我们可以将天数看做数组的下标,每一个请求都是在对一个区间的值进行修改,于是可以将本题看做一个区间修改的题目,而支持区间修改的数据结构无非就线段树和树状数组
这里使用线段树的做法
维护区间最小值,当最小值为负时返回false,输出申请人编号

code

#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(int i=start;i<=end;i++)
#define clean(arry,num); memset(arry,num,sizeof(arry));
#define min(a,b) ((a>b)?b:a)
#define max(a,b) ((a<b)?b:a)
#define ll long long
ll n,m;
const int maxn=1000000+10,maxm=1000000+10;
ll data[maxn];
ll minn[maxn<<2],lazy[maxn<<2];
inline ll read()
{
   ll ans=0;char r=getchar();bool neg=false;
   while(r<'0'||r>'9'){if(r=='-')neg=true;r=getchar();}
   while(r>='0'&&r<='9'){ans=ans*10+r-'0';r=getchar();}
   return (neg)?-ans:ans;
}
void pushup(ll rt)
{
    minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
}
void buildtree(ll nl,ll nr,ll rt)
{
    lazy[rt]=0;
    if(nl==nr)
    {
        minn[rt]=data[nl];
        return;
    }
    int m=nl+(nr-nl)/2;
    buildtree(nl,m,rt<<1);
    buildtree(m+1,nr,rt<<1|1);
    pushup(rt);
}
void pushdown(ll rt,ll len)
{
    if(!lazy[rt])return;
    lazy[rt<<1]+=lazy[rt];
    lazy[rt<<1|1]+=lazy[rt];
    minn[rt<<1]-=lazy[rt];
    minn[rt<<1|1]-=lazy[rt];
    lazy[rt]=0;
}
bool add(ll l,ll r,ll nl,ll nr,ll rt,ll num)
{
    if(l<=nl&&nr<=r)
    {
        minn[rt]-=num;
        if(minn[rt]<0)return false;
        lazy[rt]+=num;
        return true;
    }
    pushdown(rt,nr-nl+1);
    ll m=nl+(nr-nl)/2;
    bool suc=1;
    if(m>=l)suc&=add(l,r,nl,m,rt<<1,num);
    if(m<r)suc&=add(l,r,m+1,nr,rt<<1|1,num);//位运算真好用哈哈哈
    pushup(rt);
    return (suc)?true:false;
}
int main()
{
   //freopen("datain.txt","r",stdin);
   n=read();m=read();
   loop(i,1,n)data[i]=read();
   buildtree(1,n,1);
   loop(i,1,m)
   {
   		ll d,s,t;
   		d=read();s=read();t=read();
   		if(!add(s,t,1,n,1,d))
   		{
   			printf("-1\n%d",i);
   			exit(0);
        }
   }
   printf("0");
   return 0;
}
/********************************************************************
   ID:Andrew_82
   LANG:C++
   PROG:S_tree
********************************************************************/

学到的东西

  • 线段树的各种标记维护

从代码上看,线段树的核心数据其实存储在标记数组中
(如sum[maxn<<2],minn[maxn<<2])
而原数组基本没有改动,原数组的作用仅在建树时体现(因此完全可以写一个类出来~~~~~)

标记数组一般有:sum,minn,maxx(区间乘法?蒟蒻表示不会)
而每次对区间的修改其实并不发生在原数组上,只发生在标记数组上,因此在维护时,应该根据其特点来构造pushup和pushdown函数,且只对于标记数组生效

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值