题目链接
https://www.luogu.com.cn/problem/P1083
解题思路
第一种方法,也是我用的方法,因为另一种没想到。
线段树,维护区间最小值,比较简单,就是代码冗长
不会戳这里
第二种才是好方法,差分数组+二分
这道题就是我点差分数组才找到的,说来惭愧我并没用差分数组。
将二分请求出错是第几次,
check函数的话,从第一次请求到二分的这次请求循环,用差分数组记录,再循环1 ~ n求和,并比较与房间个数的大小关系,比房间多说明不可行,否则可行。
AC代码
//线段树 维护最小值 区间修改 区间查询
//提醒用scanf,printf否则可能超时
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
const int INF=0x3f3f3f3f;
int n,m,d,s,t,ans,j,rm[N];
struct TREE
{
int l,r,lazy,m;
}tr[N<<2];
void Build(int i,int l,int r)
{
tr[i].l=l;
tr[i].r=r;
tr[i].lazy=0;
tr[i].m=INF;
if(l==r)
{
tr[i].m=rm[l];
return ;
}
int mid=l+r>>1;
Build(i<<1,l,mid);
Build(i<<1|1,mid+1,r);
tr[i].m=min(tr[i<<1].m,tr[i<<1|1].m);
return ;
}
void PushDown(int i)
{
if(tr[i].lazy==0) return ;
tr[i<<1].lazy+=tr[i].lazy;
tr[i<<1|1].lazy+=tr[i].lazy;
tr[i<<1].m-=tr[i].lazy;
tr[i<<1|1].m-=tr[i].lazy;
tr[i].lazy=0;
}
void Update(int i,int l,int r,int sub)
{
if(l<=tr[i].l && tr[i].r<=r)
{
tr[i].lazy+=sub;
tr[i].m-=sub;
return ;
}
PushDown(i);
if(tr[i<<1].r>=l) Update(i<<1,l,r,sub);
if(tr[i<<1|1].l<=r) Update(i<<1|1,l,r,sub);
tr[i].m=min(tr[i<<1].m,tr[i<<1|1].m);
return ;
}
int Query(int i,int l,int r)
{
if(l<=tr[i].l && tr[i].r<=r) return tr[i].m;
if(tr[i].r<l || tr[i].l>r) return INF;
int res=INF;
PushDown(i);
if(tr[i<<1].r>=l) res=min(res,Query(i<<1,l,r));
if(tr[i<<1|1].l<=r) res=min(res,Query(i<<1|1,l,r));
tr[i].m=min(tr[i<<1].m,tr[i<<1|1].m);
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&rm[i]);
Build(1,1,n);
for(j=1;j<=m;j++)
{
scanf("%d%d%d",&d,&s,&t);
if(d>Query(1,s,t))//d大于区间最小值 break
{
ans=j;
break;
}
Update(1,s,t,d); //维护区间最小值
}
if(j>m) puts("0");
else puts("-1"),printf("%d\n",ans);
return 0;
}
//差分数组+二分
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int diff[N],rm[N],d[N],l[N],r[N],sum[N];
int n,m;
bool check(int x)
{
memset(diff,0,sizeof diff);//!
for(int i=1;i<=x;i++)
{
diff[l[i]]+=d[i];
diff[r[i]+1]-=d[i];
}
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+diff[i];
if(sum[i]>rm[i]) return 0;
}
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&rm[i]);
for(int i=1;i<=m;i++) scanf("%d%d%d",&d[i],&l[i],&r[i]);
if(check(m)) puts("0");
else
{
int ll=1,rr=m;
while(ll<rr)
{
int mid=ll+rr>>1;
if(check(mid)) ll=mid+1;
else rr=mid;
}
puts("-1");printf("%d",ll);
}
return 0;
}

京公网安备 11010502036488号