zoukankan      html  css  js  c++  java
  • 【好题】线段树优化dp——cf1334F

    /*
    用dp[i][j]来表示a[i]将要匹配b[j]时的代价
    如果a[i]没有对应的b[x]
        如果p[i]<=0,直接将这位丢掉,dp[i][j]=dp[i-1][j]+p[i]
        如果p[i]>0, 那么这位能不丢就不丢,
            对于所有的b[j]>a[i],a[i]不丢掉是不会影响第j位的匹配的,dp[i][j]=dp[i-1][j] 
            对于所有b[j]<=a[i],a[i]必须丢掉,所以 dp[i][j]=dp[i-1][j]+p[i]
    如果a[i]对应了b[x]
        可以发现,多了一种转移出来 dp[i][x+1]=dp[i-1][x],其它转移都是不会变的
        所以把dp[i-1][x]的值提前记录下来,然后在线段树更新完后再去用这个值更新dp[i][x+1] 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define N 500005
    #define ll long long 
    
    ll n,a[N],p[N],m,b[N];
    const ll INF = 1e16;
    
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    ll mi[N<<2],lazy[N<<2];
    void pushdown(int rt){
        if(lazy[rt]!=0){
            lazy[rt<<1]+=lazy[rt];
            lazy[rt<<1|1]+=lazy[rt];
            mi[rt<<1]+=lazy[rt];
            mi[rt<<1|1]+=lazy[rt];
            lazy[rt]=0;
        }
    }
    void update1(int L,int R,ll v,int l,int r,int rt){// 区间加 
        if(L>R)return;
        if(L<=l && R>=r){
            lazy[rt]+=v;mi[rt]+=v;
            return;
        }
        pushdown(rt);
        int m=l+r>>1;
        if(L<=m)update1(L,R,v,lson);
        if(R>m)update1(L,R,v,rson);
        mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
    }
    void update2(int pos,ll v,int l,int r,int rt){// 单点取min 
        if(l==r){
            mi[rt]=min(mi[rt],v);return;
        }
        pushdown(rt);
        int m=l+r>>1;
        if(pos<=m)update2(pos,v,lson);
        else update2(pos,v,rson);
        mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
    }
    ll query(int pos,int l,int r,int rt){// 单点查询 
        if(l==r)return mi[rt];
        pushdown(rt);
        int m=l+r>>1;
        if(pos<=m)return query(pos,lson);
        else return query(pos,rson);
    }
    
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        for(int i=1;i<=n;i++)scanf("%lld",&p[i]);
        cin>>m;
        for(int i=1;i<=m;i++)scanf("%lld",&b[i]);
        
        update1(2,m+1,INF,1,m+1,1);//dp[0][1]=0
        for(int i=1;i<=n;i++){
            int x=lower_bound(b+1,b+1+m,a[i])-b;
            if(x==m+1){  // a[i]必须删 
                update1(1,m+1,p[i],1,m+1,1); 
            } else {
                ll tmp=INF;
                if(a[i]==b[x])tmp=query(x,1,m+1,1);
                if(p[i]<0)
                    update1(1,m+1,p[i],1,m+1,1);
                else update1(1,x,p[i],1,m+1,1);
                if(a[i]==b[x] && tmp<INF)
                    update2(x+1,tmp,1,m+1,1);
            } 
        }
        ll res=query(m+1,1,m+1,1);
        if(res<1e15){
            puts("YES");cout<<res;
        }else {
            puts("NO");
        }
    }
  • 相关阅读:
    oracle_case when
    sql记录
    修改tomcat默认编码
    sql server_TED(透明数据加密)
    web请求过程
    freemarker 标签循环list 以及获取下标值
    鼠标操作
    窗口切换
    日历控件
    xpath定位
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12769849.html
Copyright © 2011-2022 走看看