传送门:https://www.luogu.org/problemnew/show/P1083
先说思路,代码在思路的基础上稍微改了一点,但不难理解。
【差分】维护一个差分数组,对于每一次借教室,单点修改即可。
【二分】如果仅仅用差分来解决此题,会严重超时,所以还需要结合二分来看。先判断从1~(1+m)/2天的人借教室是否合法,如果合法了,再去后半部分继续判断;若不合法,则在前半部找到具体是哪个不合法。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e6+1;
inline int read()
{
static char ch;
while((ch = getchar()) < '0' || ch > '9');
int ret = ch - 48;
while((ch = getchar()) >= '0' && ch <= '9')
ret = ret * 10 + ch - 48;
return ret;
}
int n,m,r[N],d[N],s[N],t[N],a[N],b[N],ans,ll,rr;
bool check(int mid)
{
memset(a,0,sizeof(a));
for(int i = 1;i <= mid;i++)
{
a[s[i]] += d[i];
a[t[i]+1] -= d[i];
}
for(int i = 1;i <= n;i++)
{
b[i] = b[i-1] + a[i];
if(b[i] > r[i]) return false;
}
return true;
}
int main()
{
n = read();
m = read();
for(int i = 1;i <= n;i++) r[i] = read();
for(int i = 1;i <= m;i++)
d[i] = read(),s[i] = read(),t[i] = read();
ll = 1,rr = m,ans = m + 1;
while(ll <= rr)
{
int mid = (ll + rr) >> 1;
if(check(mid)) ll = mid + 1;
else
{
rr = mid-1;
ans = min(ans,mid);
}
}
if(ans == m+1) printf("0");
else printf("-1
%d",ans);
return 0;
}