zoukankan      html  css  js  c++  java
  • 线段树优化dp(elect选择)

    好几天以前的考试题,现在才想起来调。。

    题意

    选格子,要求选出的权值最小,但每次选的格子范围有限制:abs(j-k)<=w[i][j]+w[i-1][k]   w是其另一个值

    暴力:O(n*m*m*T)

    优化:对于将要选的一行格子,将其上一行格子能够覆盖的范围处理出来,然后选这一行时,希望较快的得到在这个格子可以选的范围里面,权值最小的一格

    于是对每一行用线段树维护最小值,到了下一行就把线段树清空,重新modify

    #include<bits/stdc++.h>
    using namespace std;
    #define mid ((l+r)>>1)
    #define N 105
    #define M 5005
    #define inf 0x7f7f7f
    int a[N][M],dp[N][M],minn[M*4],fl[M*4],l[N][M],r[N][M];
    void update(int s)
    { minn[s]=min(minn[s<<1],minn[s<<1|1]); }
    void pushdown(int s)
    {
        if(fl[s]==inf) return ;
        minn[s<<1]=min(minn[s<<1],fl[s]);
        fl[s<<1]=min(fl[s<<1],fl[s]);
        minn[s<<1|1]=min(minn[s<<1|1],fl[s]);
        fl[s<<1|1]=min(fl[s<<1|1],fl[s]);
        fl[s]=inf;
    }
    void build(int s,int l,int r)
    {
        fl[s]=inf;
        if(l==r) { minn[s]=inf;  return ; }
        build(s<<1,l,mid); build(s<<1|1,mid+1,r);
        update(s);
    }
    void modify(int s,int l,int r,int L,int R,int v)
    {
        if(L<=l&&r<=R){
            minn[s]=min(minn[s],v);//一定要记得更新!! 
            fl[s]=min(fl[s],v);
            return ;
        }
        pushdown(s);//modify和query都有标记下传 
        if(L<=mid) modify(s<<1,l,mid,L,R,v);
        if(R>mid)  modify(s<<1|1,mid+1,r,L,R,v);
        update(s);
    }
    int query(int s,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R) return minn[s];
        pushdown(s);
        int ans=inf;
        if(L<=mid) ans=min(ans,query(s<<1,l,mid,L,R));
        if(R>mid)  ans=min(ans,query(s<<1|1,mid+1,r,L,R));
        return ans;
    }
    int main()
    {
        freopen("elect.in","r",stdin);
        freopen("elect.out","w",stdout);
        int T,n,m;
        scanf("%d%d%d",&T,&n,&m);
        while(T--){
            int ans=0x7f7f7f;
            for(int i=1;i<=n;i++)
             for(int j=1;j<=m;j++)
              scanf("%d",&a[i][j]);
            for(int i=1;i<=n;i++)
             for(int j=1;j<=m;j++){
                 int x;
                 scanf("%d",&x);
                 l[i][j]=max(1,j-x);//对于每一行的每一个点求出能覆盖的最远距离 用线段树维护区间最值 
                 r[i][j]=min(m,j+x);
             }
            build(1,1,m);
            for(int i=1;i<=m;i++)
             dp[1][i]=a[1][i],modify(1,1,m,l[1][i],r[1][i],dp[1][i]);
            for(int i=2;i<=n;i++){
                 for(int j=1;j<=m;j++)
                   dp[i][j]=query(1,1,m,l[i][j],r[i][j])+a[i][j];
                 build(1,1,m);//一行对应一个线段树!! 一行用完后要重建 
                 for(int j=1;j<=m;j++)
                 modify(1,1,m,l[i][j],r[i][j],dp[i][j]);
            }
            for(int i=1;i<=m;i++) ans=min(ans,dp[n][i]);
            printf("%d
    ",ans);
        }
    }
    /*
    1
    3 5
    9 5 3 8 7
    8 2 6 8 9
    1 9 7 8 6
    
    0 1 0 1 2
    1 0 2 1 1
    0 2 1 0 2
    */
  • 相关阅读:
    ExtJs学习笔记之ComboBox组件
    ExtJs学习笔记之学习小结LoginDemo
    ExtJs学习笔记之Button组件
    ExtJs学习笔记之TextField
    WAF指纹识别和XSS过滤器绕过技巧
    python中的迭代与递归
    使用Python对文档单词进行计数
    Python正则表达式使用实例
    Python十六进制与字符串的转换
    数组名a,数组名取地址&a,数组首地址&a[0],数组指针*p
  • 原文地址:https://www.cnblogs.com/mowanying/p/11222832.html
Copyright © 2011-2022 走看看