2012NOIP DAY2T1
方法1:线段树
使用线段树来维护一个区间的最小值,每次对于输入的L,R区间进行区间修改,如果最小值<0,则无法成功借教室(加了一大堆玄学优化,终于勉强没T)
#include <cstdio>
#include <stdlib.h>
using namespace std;
const int maxn=1e6+100;
struct tree{
int minn;
int l,r;
int adi;
}st[maxn*4];
int a[maxn];
int w;
inline int min(int a,int b)
{
return a < b ? a : b;
}
void build(int o,int l,int r)
{
st[o].l=l,st[o].r=r;
if(l==r)
{
st[o].minn=a[l];
return;
}
int mid=(r+l)>>1;
build((o<<1),l,mid);
build((o<<1)|1,mid+1,r);
st[o].minn=min(st[(o<<1)].minn,st[(o<<1)|1].minn);
}
inline void push_down(int o)
{
int add=st[o].adi;
st[o].adi=0;
st[(o<<1)].adi+=add;
st[(o<<1)|1].adi+=add;
st[(o<<1)].minn+=add;
st[(o<<1)|1].minn+=add;
}
inline void query(int o,int ql,int qr,int ad)
{
int l=st[o].l,r=st[o].r;
if(l==ql&&r==qr)
{
st[o].adi+=ad;
st[o].minn+=ad;
if(st[o].minn<0)
{
printf("-1\n%d\n",w);
exit(0);
}
return;
}
if(st[o].adi) push_down(o);
int mid=(l+r)>>1;
if(qr<=mid) query((o<<1),ql,qr,ad);
else if(ql>mid) query((o<<1)|1,ql,qr,ad);
else query((o<<1),ql,mid,ad),query((o<<1)|1,mid+1,qr,ad);
st[o].minn=min(st[(o<<1)].minn,st[(o<<1)|1].minn);
}
inline int read()
{
int data=0,w=1; char ch=0;
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
return data*w;
}
int main()
{
int n,m;
n=read();
m=read();
for (int i = 1; i <= n; i++)
{
char c = getchar();
while(c < '0' || c > '9')
c = getchar();
while(c >= '0' && c <= '9')
{
a[i] *= 10;
a[i] += c - '0';
c = getchar();
}
}
build(1,1,n);
for(int i=1;i<=m;i++)
{
int x,y,t;
t=read();
x=read();
y=read();
w=i;
query(1,x,y,-t);
}
printf("0");
return 0;
}
方法2:二分+差分
二分能够成功的方案数,用差分进行区修改,暴力判断有没有超出限制的,时间复杂度O(nlogn)
其实跟线段树的复杂度相同,只是常数比较小,在数据爆炸的题里会快不少!
#include <cstdio>
#include <stdlib.h>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=1001000;
struct tree{
int l,r,t;
}a[maxn];
int d[maxn];
int b[maxn];
inline int read()
{
int data=0,w=1; char ch=0;
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
return data*w;
}
int n,m;
inline bool check(int mid)
{
memset(b,0,sizeof(b));
for(int i=1;i<=mid;i++)
b[a[i].l]+=a[i].t,b[a[i].r+1]-=a[i].t;
int s=0;
for(int i=1;i<=n;i++)
{
s+=b[i];
if(s>d[i])
return 0;
}
return 1;
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
d[i]=read();
for(int i=1;i<=m;i++)
a[i].t=read(),a[i].l=read(),a[i].r=read();
int l=1;
int r=m;
int ans=0;
while(l<=r)
{
int mid=(l+r)/2;
if(!check(mid))
ans=mid,r=mid-1;
else
l=mid+1;
}
if(!ans)
printf("0");
else
printf("-1\n%d",ans);
return 0;
}