zoukankan      html  css  js  c++  java
  • XJOI 夏令营501-511NOIP训练14 砍树(2)

    小A是小B家的园丁。小B的家里有n棵树,第i棵树的横坐标为i。一天,小B交给小A一个任务,让他降低自己家中的某些树木的高度。这个任务对小A来说十分简单,因为他有一把极其锋利的斧头和一门独门砍树秘籍,能够轻易地砍断任何参天大树。小A的砍树方法有3种,都是沿着一条y=kx+b的直线砍一段区间的树,相同的方法k值相同。只用了一个下午,小A就完成了小B的任务。第二天,小B来视察小A的任务完成情况。小B想知道小A是否真的用心砍树,于是提出了q个询问,每次询问一段区间中最低的树的高度。小A当然是不会记住树木的砍伐情况的,他只知道自己按什么顺序,使用了什么方法,砍了哪个连续区间的树,而且区间都是互不包含的。现在小A想请你帮帮他,回答小B的询问。

    输入格式:

    第一行三个整数k1,k2,k3表示小A三种砍树方法的斜率值;
    第二行一个数n,表示一共有n棵树;
    第三行n个数hi,分别表示n棵树的高度;
    第四行一个数m,表示小A一共进行了m次操作;
    接下来m行,每行四个数L,R,p,b,表示用第p种方法,即用y=kp+b的直线砍[L,R]区间的树;
    接下来一行一个数q,表示小B的询问数;
    接下来q行,每行两个数L,R,表示询问[L,R]区间中最低的树的高度。

    输出格式:

    一共q行,每行一个数h表示对应的回答。

    样例输入:

    1 0 -1
    4
    10 30 20 1
    2
    3 4 2 5
    1 3 3 10
    2
    1 2
    2 3
    

    样例输出:

    8
    5

    数据范围:

    n<=1000000,m<=500000

    时间限制:

    3s

    空间限制:

    64M

    提示:

    如下图,红色即为树的剩余部分。
    1.jpg

    线段树

    对于三种砍伐方法,每种砍得过程中k都是一样,只是b不一样

    但是对于对树木影响最大的一定是b最小的时候

    那么对于h数组建出线段树,开出三个lazy标记,分别表示这三种k的最小b

    并同时记录区间最小值

    在pushdown时,要对k分类讨论

    如果$k<0$,这次砍树的最低点在最右端

    如果$k>0$,这次砍树的最低点在最左端

    然后就是区间修改,区间询问

    还有这道题空间开的很卡,要用动态开点的线段树写法

    #include <bits/stdc++.h>
    #define inf 1000000000
    using namespace std;
    const int MAXN=1000010;
    int k[4],n,h[MAXN],m,q,w;
    struct node
    {
        int la[3],MIN,ls,rs;
    }sh[MAXN*2];
    void pushup(int x)
    {
        sh[x].MIN=min(sh[sh[x].ls].MIN,sh[sh[x].rs].MIN);
    }
    void pushdown(int x,int l,int r)
    {
        int mid;
        mid=(l+r)>>1;
        for (int i=0;i<=2;i++)
        {
            if (sh[x].la[i]!=inf)
            {
                if (k[i]<0)//同上分类讨论
                {
                    sh[sh[x].ls].MIN=min(sh[sh[x].ls].MIN,max(k[i]*mid+sh[x].la[i],0));
                    sh[sh[x].rs].MIN=min(sh[sh[x].rs].MIN,max(k[i]*r+sh[x].la[i],0));
                }
                else
                {
                    sh[sh[x].ls].MIN=min(sh[sh[x].ls].MIN,max(k[i]*l+sh[x].la[i],0));
                    sh[sh[x].rs].MIN=min(sh[sh[x].rs].MIN,max(k[i]*(mid+1)+sh[x].la[i],0));
                }
                sh[sh[x].ls].la[i]=min(sh[sh[x].ls].la[i],sh[x].la[i]);//注意不是直接赋值,而是取最小值符合定义
                sh[sh[x].rs].la[i]=min(sh[sh[x].rs].la[i],sh[x].la[i]);
                sh[x].la[i]=inf;
            }
        }
    }
    int build(int ll,int rr)//动态开点
    {
        w++;
        int now=w;
        for (int i=0;i<=2;i++)
          sh[now].la[i]=inf;
        if (ll==rr)
        {
            sh[now].MIN=h[ll];
            return now;
        }
        int mid;
        mid=(ll+rr)>>1;
        sh[now].ls=build(ll,mid);
        sh[now].rs=build(mid+1,rr);
        pushup(now);
        return now;
    }
    void change(int x,int l,int r,int ll,int rr,int kind,int v)//区间修改
    {
        if (l>=ll && r<=rr)
        {
            if (v<sh[x].la[kind])
            {
                sh[x].la[kind]=v;
                if (k[kind]>0)
                  sh[x].MIN=min(sh[x].MIN,max(l*k[kind]+v,0));
                else
                  sh[x].MIN=min(sh[x].MIN,max(r*k[kind]+v,0));
            }
            return;
        }
        pushdown(x,l,r);
        int mid;
        mid=(l+r)>>1;
        if (ll<=mid)
          change(sh[x].ls,l,mid,ll,rr,kind,v);
        if (rr>mid)
          change(sh[x].rs,mid+1,r,ll,rr,kind,v);
        pushup(x);
    }
    int query(int x,int l,int r,int ll,int rr)//区间查询
    {
        if (l>=ll && r<=rr)
          return sh[x].MIN;
        pushdown(x,l,r);
        pushup(x);
        int mid,ans;
        ans=inf;
        mid=(l+r)>>1;
        if (ll<=mid)
          ans=query(sh[x].ls,l,mid,ll,rr);
        if (rr>mid)
          ans=min(ans,query(sh[x].rs,mid+1,r,ll,rr));
        return ans;
    }
    int main()
    {
        for (int i=0;i<=2;i++)
          scanf("%d",&k[i]);
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
          scanf("%d",&h[i]);
        build(1,n);
        scanf("%d",&m);
        for (int i=1;i<=m;i++)
        {
            int l,r,p,b;
            scanf("%d%d%d%d",&l,&r,&p,&b);
            change(1,1,n,l,r,p-1,b);
        }
        scanf("%d",&q);
        for (int i=1;i<=q;i++)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%d
    ",query(1,1,n,l,r));
        }
    }
  • 相关阅读:
    delphi7在windows server 2003企业版上不能打开项目的选项(Options)窗口的解决方法
    简单的两个字“谢谢”,会让我坚持我的写作,我也要谢谢你们
    F41GUT 安装Windows server 2003系统后无法安装显卡驱动的解决办法
    远程桌面无法登录windows server 2003服务器
    F41GUT 安装Windows server 2003系统后无法安装显卡驱动的解决办法
    MS SQL Server 2000版在windows server 2003企业版系统上运行时造成数据库suspect的解决方法
    delphi7在windows server 2003企业版上不能打开项目的选项(Options)窗口的解决方法
    远程桌面无法登录windows server 2003服务器
    MS SQL Server 2000版在windows server 2003企业版系统上运行时造成数据库suspect的解决方法
    关于ajax 和josn
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/11265286.html
Copyright © 2011-2022 走看看