题目大意:
有数列An,每次我们可以选择一个区间做减法,问我们第几次操作会导致一个区间出现负数。
n<=1e6
解题思路:线段树是可以做的,但是貌似这题卡了线段树。这里使用二分枚举答案的方法。为什么这里适合用差分呢?因为这里满足false false ... true ... false的结构。每次枚举到一个点时,我们对指定线段做差分然后用前缀和恢复,最后做到复杂度O(nlogn) 其中logn是二分带来的,n是做差分带来的。
#include <bits/stdc++.h>
using namespace std;
typedef struct{
int d,l,r;
}inp;
int main(){
int n,m;cin>>n>>m;
vector<int> arrmv(n+1,0);
for(int i=1;i<=n;i++)
cin>>arrmv[i];
vector<inp> in;
inp dummy;
in.push_back(dummy);
for(int i=0;i<m;i++){
inp t;
cin>>t.d>>t.l>>t.r;
in.push_back(t);
}
int x=1;int y=m+1;
while(x<y){
int mid=x+(y-x)/2;
vector<int> dif(n+2,0);
for(int i=1;i<=mid;i++){
dif[in[i].l]-=in[i].d;
dif[in[i].r+1]+=in[i].d;
}
for(int i=1;i<=n;i++){
dif[i]+=dif[i-1];
}
vector<int> tmp=arrmv;
int suc=1;
for(int i=1;i<=n;i++){
tmp[i]+=dif[i];
if(tmp[i]<0){
suc=0;
break;
}
}
if(suc){
x=mid+1;
}else y=mid;
}
if(y==m+1){
cout<<0<<endl;
}else{
cout<<-1<<endl;
cout<<x<<endl;
}
return 0;
}