• NOIP 模拟 $16; m God Knows$


    题解 (by;zjvarphi)

    对于这道题,不难想到可以用 (dp),就是求一个最小权极长上升子序列

    (dp_i) 表示最后一个选 (i) 时,覆盖前 (i) 条边的最小花费,设 ( m l_i) 表示第 ( m i) 条边前第一个 (p)(i) 小的位置

    那么能对 (dp_i) 转移的就是从 ( m l_i) 往前的 (p) 上升的序列,这个东西要暴力转移的话,会达到 (n^2)

    考虑线段树优化单调栈,用一棵线段树 (log^2n) 维护,具体如何请看代码

    Code
    #include<bits/stdc++.h>
    #define ri register signed
    #define p(i) ++i
    using namespace std;
    namespace IO{
        char buf[1<<21],*p1=buf,*p2=buf;
        #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
        template<typename T>inline void read(T &x) {
            ri f=1;x=0;register char ch=gc();
            while(ch<'0'||ch>'9') {if (ch=='-') f=0;ch=gc();}
            while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
            x=f?x:-x;
        }
    }
    using IO::read;
    namespace nanfeng{
        #define FI FILE *IN
        #define FO FILE *OUT
        template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
        template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
        static const int N=2e5+7,INF=1e9+7;
        int dp[N],p[N],c[N],rmx,tmp,n,ans=INF;
        struct Seg{
            #define ls(x) (x<<1)
            #define rs(x) (x<<1|1)
            struct segmenttree{int mx,mn;segmenttree(){mn=INF;}}T[N<<2];
            int calc(int x,int l,int r,int w) {
                if (T[x].mx<=w) return INF; //记录一个 mx表示区间最大的 i,如果区间最大都不比限制大,那么直接返回 
                if (l==r) return dp[T[x].mx];
                int mid(l+r>>1);
                if (T[rs(x)].mx<w) return calc(ls(x),l,mid,w);//如果右区间不可以,就寻找左区间
                return cmin(T[x].mn,calc(rs(x),mid+1,r,w));//记录一个 mn 表示,当前节点在右儿子 mx 的限制下,左儿子的贡献
            }
            int query(int x,int lt,int rt,int l,int r) {
                if (l<=lt&&rt<=r) 
                    return tmp=rmx,rmx=cmax(rmx,T[x].mx),calc(x,lt,rt,tmp);//找到一段区间,询问
                int mid(lt+rt>>1),res(INF);
                if (r>mid) res=cmin(res,query(rs(x),mid+1,rt,l,r));//一定要先找右儿子,更新 rmx 这个限制
                if (l<=mid) res=cmin(res,query(ls(x),lt,mid,l,r));
                return res;
            }
            void update(int x,int k,int p,int l,int r) {
                if (l==r) return (void)(T[x].mx=k);
                int mid(l+r>>1);
                if (p<=mid) update(ls(x),k,p,l,mid); 
                else update(rs(x),k,p,mid+1,r);
                T[x].mn=calc(ls(x),l,mid,T[rs(x)].mx);//更新时记得更 mn
                T[x].mx=cmax(T[ls(x)].mx,T[rs(x)].mx);
            }
        }T;//这样可以保证线段树是每次递归左右儿子中的一个,复杂度 log^2n
        inline int main() {
            // FI=freopen("nanfeng.in","r",stdin);
            // FO=freopen("nanfeng.out","w",stdout);
            read(n);
            for (ri i(1);i<=n;p(i)) read(p[i]);
            for (ri i(1);i<=n;p(i)) read(c[i]);
            for (ri i(1);i<=n;p(i)) {
                rmx=0;
                dp[i]=((tmp=T.query(1,1,n,1,p[i]))<INF?tmp:0)+c[i];
                T.update(1,i,p[i],1,n);
            }
            for (ri i(n),mx(0);i;--i) if (p[i]>mx) ans=cmin(ans,dp[i]),mx=p[i];
            printf("%d
    ",ans);
            return 0;
        }  
    }
    int main() {return nanfeng::main();} 
    
  • 相关阅读:
    寒假作业1
    自我介绍
    我罗斯方块1
    我罗斯方块
    解题报告 数学2
    解题报告 转化模式
    解题报告 数学
    经典语录
    解题报告 Trick
    解题报告 帮忙
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/15019506.html
Copyright © 2020-2023  润新知