借教室

来源:互联网 发布:java 阻塞排查 编辑:程序博客网 时间:2024/04/28 11:07

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;}
原创粉丝点击