洛谷 1083 (NOIp2012) 借教室——标记永久化线段树 / 差分+二分

题目:https://www.luogu.org/problemnew/show/P1083

听说线段树不标记永久化会T一个点。

注意mn记录的是本层以下、带上标记的min!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+5,INF=1e9+5;
int n,m,a[N],L,R,w,tot,ls[N<<1],rs[N<<1],mn[N<<1],laz[N<<1];
bool flag;
int rdn()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar();
    return ret;
}
void pshp(int cr)
{
    mn[cr]=min(mn[ls[cr]],mn[rs[cr]])-laz[cr];//-laz[cr]!!
}
void build(int l,int r,int cr)
{
    mn[cr]=INF;
    if(l==r){mn[cr]=a[l];return;}
    int mid=l+r>>1;
    ls[cr]=++tot;build(l,mid,ls[cr]);
    rs[cr]=++tot;build(mid+1,r,rs[cr]);
    pshp(cr);
}
void mdfy(int l,int r,int cr,int lj)
{
    if(l>=L&&r<=R)
        {laz[cr]+=w;mn[cr]-=w;return;}
    int mid=l+r>>1;
    if(L<=mid)mdfy(l,mid,ls[cr],lj+laz[cr]);
    if(mid<R)mdfy(mid+1,r,rs[cr],lj+laz[cr]);
    pshp(cr);
}
int main()
{
    n=rdn();m=rdn();
    for(int i=1;i<=n;i++)a[i]=rdn();
    tot=1;build(1,n,1);int i;
    for(i=1;i<=m;i++)
    {
        w=rdn();L=rdn();R=rdn();
        mdfy(1,n,1,0);
        if(mn[1]<0)break;
    }
    if(i==m+1)printf("0\n");
    else printf("-1\n%d\n",i);
    return 0;
}
View Code

然而用每次遍历一下整个数组的二分答案也能做到nlogn。

注意不要把c[ ]弄成真的差分,再弄一个yc[ ]每次memcpy,不然比线段树还慢。如果把减弄成加,每次memset成0,就能快很多。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+5;
int n,m,a[N],c[N],l[N],r[N],d[N];
bool pan(int k)
{
    memset(c,0,sizeof c);
    for(int i=1;i<=k;i++)c[l[i]]+=d[i],c[r[i]+1]-=d[i];
    for(int i=1,sum=0;i<=n;i++)
    {
        sum+=c[i];
        if(sum>a[i])return true;
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&d[i],&l[i],&r[i]);
    int l=1,r=m,ans=0;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(pan(mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
    if(!ans)printf("0\n");
    else printf("-1\n%d\n",ans);
    return 0;
}

 

posted on 2018-08-04 20:34  Narh  阅读(305)  评论(0编辑  收藏  举报

导航