emmm,不知道说什么,线段树吧,不过不进行区间修改的裸的线段树是不行的,比暴力分还低,我们应该想到区间修改求最小值,也就是把初值赋成每天的教室数量,然后求最小值即可。
区间修改自然是要加lazy
但是,我们不需要求出最小值的值是多少,因此,我们不需要单独找一遍区间最小值,直接在进行区间减的时候进行判断,判断是否有某个区间的最小值<0即可!!当然,速度超快的哦!-_-关键呢!
想到+lazy ->95
想到不单独求最小值 ->100
没什么用的PS:其实不用像我这么加这么多判断,主要是刚想出来的时候有点激动^_^
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 3000005
#define inf 0x3f3f3f3f
using namespace std;
inline int wread (){
char c(getchar ());int wans(0),flag(1);
while (c<'0' || c>'9'){if (c=='-') flag=-1;c=getchar ();}
while (c>='0' && c<='9'){wans=wans*10+c-'0';c=getchar ();}
return wans*=flag;
}
int n,m;
struct node {int l,r,lazy,minx;}tre[4*N];
bool F=false;//用来判断
inline int min (int x,int y){return x<y?x:y;}
//建树
inline void make_tre (int a,int l,int r){
tre[a].l=l;tre[a].r=r;tre[a].lazy=0;tre[a].minx=inf;
if (l==r) {tre[a].minx=wread();return;}
int mid(l+r>>1),lson(a<<1),rson(a<<1|1);
make_tre (lson,l,mid);make_tre (rson,mid+1,r);
tre[a].minx=min (tre[lson].minx,tre[rson].minx);
return ;
}
//下放
inline void xia_fang (int a){
if (!tre[a].lazy) return;
int lson(a<<1),rson(a<<1|1),lz(tre[a].lazy);
tre[lson].lazy+=lz; tre[lson].minx-=lz;
if (tre[lson].minx<0) {F=true;return ;}
tre[rson].lazy+=lz; tre[rson].minx-=lz;
if (tre[rson].minx<0) {F=true;return ;}
tre[a].lazy=0;
return;
}
//区间修改+判断
inline void add_qu (int a,int l,int r,int num){
if (F) return ;//判断
if (tre[a].l>=l && tre[a].r<=r){
tre[a].lazy+=num; tre[a].minx-=num;
if (tre[a].minx<0) F=true;//判断
return ;
}
xia_fang(a);
if (F) return ;//判断
int mid(tre[a].l+tre[a].r>>1),lson(a<<1),rson(a<<1|1);
if (r<=mid) {add_qu (lson,l,r,num);if (F) return ;}//判断
else if (l>mid) {add_qu (rson,l,r,num);if (F) return ;}//判断
else {
add_qu (lson,l,r,num);
if (F) return ;//判断
add_qu (rson,l,r,num);
if (F) return ;//判断
}
tre[a].minx=min (tre[lson].minx,tre[rson].minx);
return ;
}
int main (){
n=wread();m=wread();
make_tre(1,1,n);
for (register int i=1;i<=m;++i){
int di(wread()),si(wread()),ti(wread());
add_qu(1,si,ti,di);
if (F) {
printf("-1\n%d\n",i);
return 0;
}
}
puts("0");
return 0;
}
45分暴力:(落谷)
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define N 1000006
using namespace std;
inline int wread(){
char c=getchar ();int flag=1,wans=0;
while (c<'0'||c>'9'){if (c=='-') flag=-1;c=getchar ();}
while (c>='0'&&c<='9'){wans=wans*10+c-'0';c=getchar ();}
return wans*=flag;
}
int n,m;
int ri[N];
int main (){
n=wread();m=wread();
for (int i=1;i<=n;++i)
ri[i]=wread();
for (int i=1;i<=m;++i){
int di=wread(),si=wread(),ei=wread();
//
for (int j=si;j<=ei;++j){
ri[j]-=di;
if (ri[j]<0) {
puts ("-1");
printf("%d\n",i);
return 0;
}
}
}
puts ("0");
return 0;
}
本题收获:
1. 线段树有区间修改的时候不打lazy会凉凉~
2. 要动脑筋思考进行转换-> 区间最小值,最大值,区间求和(常见的线段树区间查询操作)