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));
        }
    }
  • 相关阅读:
    zookeeper开源客户端curator
    elastic-job(lite)使用的一些注意事项
    zookeeper典型应用场景之一:master选举
    zookeeper学习笔记
    spring-boot子模块打包的jar中去掉BOOT-INF文件夹
    win10如何找回自带的照片查看器
    Hbase shell详情
    linux tar.gz zip 解压缩 压缩命令
    Java中Volatile关键字详解
    系统变量之System.getenv()和System.getProperty()
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/11265286.html
Copyright © 2011-2022 走看看