• 【简】题解 AWSL090429 【原子】


    预处理出每个原子最近的不能合并的位置

    枚举当前位置和前面断开的位置合并

    发现还是不能过

    考虑用选段树优化

    但是因为每次转移的最优点是在前面可以合并的范围内 dp值加上当前的到该点的最大值

    因为每个位置的最大值每次更新不是只更新一个位置 

    是一次更新一段位置

    所以直接维护复杂度爆炸

    有种方法(套路) 是把最值的更新改为值的加减

    因为每次是更新一段区间

    且每个点到当前的位置的最值是单调不减的

    所以每次的修改就可以是一段一段的

    可以用单调栈来维护每种值的区间

    就可以进行区间修改

    #include<bits/stdc++.h> 
    using namespace std;
    #define ll long long
    #define C getchar()-48
    inline ll read()
    {
        ll s=0,r=1;
        char c=C;
        for(;c<0||c>9;c=C) if(c==-3) r=-1;
        for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c;
        return s*r;
    } 
    const int N=1e5+10,inf=1e9; 
    int n,qm;
    int p[N],v[N],q[N];
    int vis[N];
    int dp[N];
    int dv[N],dr[N],top;
    struct xin{
        int del,mn;
    }tr[N<<2];
    inline void up(int x)
    {
        tr[x].mn=min(tr[x<<1].mn,tr[x<<1|1].mn)+tr[x].del;
    }
    inline void down(int x)
    {
        tr[x<<1].del=tr[x<<1|1].del=tr[x].del;
        tr[x].del=0;
    }
    inline void add(int x,int l,int r,int ql,int qr, int v)
    {
        if(ql<=l&&r<=qr){tr[x].del+=v,tr[x].mn+=v;return;}
        int mid=(l+r)>>1;
        if(ql<=mid) add(x<<1,l,mid,ql,qr,v);
        if(mid<qr) add(x<<1|1,mid+1,r,ql,qr,v);
        up(x);
    }
    inline int ask(int x,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr){return tr[x].mn;}
        int mid=(l+r)>>1,mn=inf;
        if(ql<=mid) mn=min(mn,ask(x<<1,l,mid,ql,qr));
        if(mid<qr) mn=min(mn,ask(x<<1|1,mid+1,r,ql,qr));
        up(x); 
        return mn+tr[x].del;
    }
    int main()
    {
        freopen("array.in","r",stdin); 
        freopen("array.out","w",stdout); 
        n=read();qm=n;vis[0]=1;dv[0]=inf;dr[0]=0;
        for(int i=1;i<=n;i++) p[i]=read(),v[i]=read();
        for(int i=n;i>=1;i--)
        {
            while(!vis[p[qm]]){vis[p[qm]]=1;qm--;}
            q[i]=qm;
            vis[p[i]]=0;
        }
        for(int i=1;i<=n;i++)
        {
            add(1,1,n,i,i,v[i]);
            while(dv[top]<v[i])
            {
                add(1,1,n,dr[top-1]+1,dr[top],v[i]-dv[top]);
                top--;
            }
            dv[++top]=v[i],dr[top]=i;
            dp[i]=ask(1,1,n,q[i]+1,i);
            add(1,1,n,i+1,i+1,dp[i]);
        }
        cout<<dp[n];
        return 0;
    }

    还有位大佬用multiset维护

    #include<bits/stdc++.h>
      using namespace std;
    
    #define Abigail inline void
    typedef long long LL;
    
    const int N=100000,INF=(1<<30)-1;
    
    multiset<int>t;
    int n,a[N+9],b[N+9],data[N+9],last[N+9],l[N+9];
    int sum[N+9],wei[N+9],f[N+9],hd,tl;
    
    Abigail into(){
      scanf("%d",&n);
      for (int i=1;i<=n;++i)
        scanf("%d%d",&a[i],&b[i]);
    }
    
    Abigail work(){
      for (int i=1;i<=n;++i)
        l[i]=max(l[i-1],last[a[i]]+1),last[a[i]]=i;
      //预处理每一个位置为结尾可以取的转移的区间左端点 
      hd=1;
      int k;
      for (int i=1;i<=n;++i){
          k=i-1;
          for (;hd<tl&&wei[hd+1]<l[i];++hd)
            t.erase(t.find(sum[hd]));
          //把不在转移区间的位置去掉 
          for (;hd<=tl&&b[i]>data[tl];--tl)
            t.erase(t.find(sum[tl])),k=wei[tl];
          //更新阶梯型(max{b[j]..b[i]})
          data[++tl]=b[i];
          wei[tl]=k;
          //加入第i个位置 
          if (hd^tl){
            sum[tl]=f[wei[tl]]+data[tl];
            //把位置i所在的阶梯中最优的值sum[tl]计算出来 
            t.insert(sum[tl]);
            //加入set中 
            t.erase(t.find(sum[hd]));
            //开头的那一段阶梯中会有一部分不可取,一部分可取 
          }
          sum[hd]=f[l[i]-1]+data[hd];
          //采取开头最优的那段 
          t.insert(sum[hd]);
          //加入set中 
          f[i]=*t.begin();
      }
    }
    
    Abigail outo(){
      printf("%d
    ",f[n]);
    }
    
    int main(){
      freopen("array.in","r",stdin);
      freopen("array.out","w",stdout);
      into();
      work();
      outo();
      return 0;
    }
  • 相关阅读:
    2019年春阅读笔记13——分布式系统的两种方式
    2019年春阅读笔记12——索引数据结构设相关的计算机原理
    2019年春阅读笔记11——常见的查询算法及数据结构
    2019年春阅读笔记10——数据库优化
    2019年春阅读笔记9——一些基础优化
    2019年春阅读笔记8——从不同层面进行SQL优化
    2019年春阅读笔记7——关于SQL优化
    2019年春阅读笔记6——继续说开源
    jQuery使用小技巧
    marquee 实现首尾相连循环滚动效果
  • 原文地址:https://www.cnblogs.com/1436177712qqcom/p/10806208.html
Copyright © 2020-2023  润新知