zoukankan      html  css  js  c++  java
  • 洛谷 P1083 [ NOIP 2012 ] 借教室 —— 线段树 / 二分差分数组

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

    当初不会线段树的时候做这道题...对差分什么不太熟练,一直没A,放在那儿不管...

    现在去看,线段树就直接秒了;

    不过要注意一下基本的细节囧...

    但本题 n 的范围比较微妙,正常线段树会 T 一个点(不过运气好也能过);

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const maxn=1e6+5,maxm=2e7+5;
    int n,m,a[maxn],mn[maxm],ls[maxm],rs[maxm],cnt=1,lzy[maxm];//cnt=1!!
    bool fl=0;
    void pushup(int x){mn[x]=min(mn[ls[x]],mn[rs[x]]);}
    void pushdown(int x)
    {
        if(!lzy[x])return;
        lzy[ls[x]]+=lzy[x]; lzy[rs[x]]+=lzy[x];
        mn[ls[x]]+=lzy[x]; mn[rs[x]]+=lzy[x];
        lzy[x]=0;
    }
    void build(int x,int l,int r)
    {
        if(l==r){mn[x]=a[l]; return;}
        int mid=((l+r)>>1);
        ls[x]=++cnt; build(ls[x],l,mid);
        rs[x]=++cnt,build(rs[x],mid+1,r);
        pushup(x);
    }
    void update(int x,int l,int r,int L,int R,int val)
    {
        if(l>=L&&r<=R){mn[x]+=val; lzy[x]+=val; return;}
        pushdown(x); int mid=((l+r)>>1);
        if(mid>=L)update(ls[x],l,mid,L,R,val);
        if(mid<R)update(rs[x],mid+1,r,L,R,val);
        pushup(x);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        build(1,1,n);
        for(int i=1,s,t,r;i<=m;i++)
        {
            scanf("%d%d%d",&r,&s,&t);
            if(fl)continue;
            update(1,1,n,s,t,-r);
            if(mn[1]<0){printf("-1
    %d
    ",i); fl=1;}
        }
        if(!fl)printf("0
    ");
        return 0;
    }
    T #13

    所以要加个标记永久化。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const maxn=1e6+5,maxm=2e7+5;
    int n,m,a[maxn],mn[maxm],ls[maxm],rs[maxm],cnt=1,lzy[maxm];//cnt=1!!
    bool fl=0;
    void pushup(int x){mn[x]=min(mn[ls[x]]+lzy[ls[x]],mn[rs[x]]+lzy[rs[x]]);}//+!
    void build(int x,int l,int r)
    {
        if(l==r){mn[x]=a[l]; return;}
        int mid=((l+r)>>1);
        ls[x]=++cnt; build(ls[x],l,mid);
        rs[x]=++cnt,build(rs[x],mid+1,r);
    //    pushup(x);
        mn[x]=min(mn[ls[x]],mn[rs[x]]);//
    }
    void update(int x,int l,int r,int L,int R,int val)
    {
        if(l==L&&r==R){lzy[x]+=val; return;}
        int mid=((l+r)>>1);
        if(mid<L)update(rs[x],mid+1,r,L,R,val);
        else if(mid>=R)update(ls[x],l,mid,L,R,val);
        else update(ls[x],l,mid,L,mid,val),update(rs[x],mid+1,r,mid+1,R,val);
        pushup(x);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        build(1,1,n);
        for(int i=1,s,t,r;i<=m;i++)
        {
            scanf("%d%d%d",&r,&s,&t);
            if(fl)continue;
            update(1,1,n,s,t,-r);
            if(mn[1]-lzy[1]<0){printf("-1
    %d
    ",i); fl=1;}
        }
        if(!fl)printf("0
    ");
        return 0;
    }

     还有一种二分差分数组的做法,其实很暴力;

    不是开两个差分数组每次 memcpy ,而是只开一个记录减少量和原数组比较,会快一点。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const maxn=1e6+5;
    int n,m,s[maxn],t[maxn],c[maxn],r[maxn],d[maxn];
    bool ck(int mid)
    {
        memset(c,0,sizeof c);
        for(int i=1;i<=mid;i++)c[s[i]]+=r[i],c[t[i]+1]-=r[i];
        bool fl=0; int tmp=0;
        for(int i=1;i<=n;i++)
        {
            tmp+=c[i];
            if(d[i]-tmp<0){fl=1; break;}
        }
        return fl;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,x,pre=0;i<=n;i++)scanf("%d",&d[i]);
        for(int i=1;i<=m;i++)scanf("%d%d%d",&r[i],&s[i],&t[i]);
        int l=1,r=m,ans=-1;
        while(l<=r)
        {
            int mid=((l+r)>>1);
            if(ck(mid))ans=mid,r=mid-1;
            else l=mid+1;
        }
        if(ans==-1)printf("0
    ");
        else printf("-1
    %d
    ",ans);
        return 0;
    }
  • 相关阅读:
    Visual Studio 编译使用 Trilinos中 Belos库 求解线性方程组 (待续)
    Visual Studio编译使用CLAPACK
    Visual Studio 页面文件太小,无法完成操作
    wpf中的BringToFront
    想买的书
    远程桌面使用matlab报错License Manager Error -103的解决办法
    工厂模式-理解Spring的Bean工厂(马士兵经典例子)
    面向对象、继承封装、多态小例子(马士兵)
    检查pod版本及更新pod
    mac之开发中的环境配置
  • 原文地址:https://www.cnblogs.com/Zinn/p/9419433.html
Copyright © 2011-2022 走看看