蓝桥杯备考-----》差分数组+二分答案 借教室
这道题我们第一个想法就是差分数组,但是差分数组的话我们每进行完一次操作都要还原一下数组看看有没有违规的值,时间复杂度就是n平方了,那就和暴力没啥区别了呀》
第二个想法一定是线段树,but 杀鸡焉用牛刀
我们可以用二分答案配合差分数组
什么意思呢?
我们的订单编号是有个二段性的
这时候我们的时间复杂度就是logM*N了,
#include <iostream>
using namespace std;
int n,m;//n表示一共几天 m表示几个订单
const int N = 1e6+10;
int a[N];//第i天的教室剩余量
int d[N],s[N],t[N];
int f[N];
typedef long long ll;
bool check(int x)
{
for(int i = 1;i<=n;i++)//构建差分数组
{
f[i] = a[i]-a[i-1];
}
for(int i = 1;i<=x;i++)
{
f[s[i]]-=d[i];
f[t[i]+1]+=d[i];
}
for(int i = 1;i<=n;i++)
{
f[i] = f[i-1]+f[i];
if(f[i] < 0) return false;
}
return true;
}
int main()
{
cin >> n >> m;
for(int i = 1;i<=n;i++)
{
cin >> a[i];
}
for(int i = 1;i<=m;i++)
{
cin >> d[i] >> s[i] >> t[i];
}
//我们需要找到第一个订单错误的编号,
//如果我们用差分数组的话,每次区间加完之后还要还原一下原数组,时间复杂度是O(N平方)
// 最好的解决办法就是线段树,but 杀鸡焉用牛刀?
//我们可以用二分答案+差分数组来做。
ll l = 1,r=m;
while(l<r)
{
ll mid = (l+r)/2;
if(check(mid)) l = mid+1;
else r = mid;
}
if(check(l)) cout << 0 << endl;
else {
cout << -1 << endl;
cout << l << endl;
}
return 0;
}