zoukankan      html  css  js  c++  java
  • 题解 洛谷 P5897 【[IOI2013]wombats 】

    发现行数比较大,列数比较小,考虑用线段树来维护行的情况,记录列对应的信息。

    (f_{i,j}) 在当前线段树节点维护的区间,从上边界 (i) 位置到下边界 (j) 位置的最小花费,为方便合并,实际处理的为跨过了下边界的最小花费。

    每次像 (Floyd) 一样合并的复杂度为 (O(m^3)),所以要考虑优化。发现任意两条最优路径不会相交,因为如果相交,其中一条一定能调整为更优的路径。因此转移有决策单调性,这样每次合并的复杂度就为 (O(m^2)) 了。

    发现开不下线段树的空间。于是对行进行分块,对于每块进行 (O(nm^2))(DP) 来处理信息,线段树的叶子节点就是每个块。

    设块大小为 (S),修改次数为 (T),询问次数为 (Q),则时间复杂度为 (O(nm^2+Tm^2(logfrac{n}{S}+S)+Q)),空间复杂度为 (O(nm+frac{n}{S}m^2))

    #include<bits/stdc++.h>
    #define maxn 5010
    #define maxm 210
    #define maxt 1010
    #define ls (cur<<1)
    #define rs (cur<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,m,q,S=20,root=1;
    int bel[maxn],L[maxn],R[maxn],v1[maxn][maxm],v2[maxn][maxm],p[maxm][maxm];
    struct node
    {
        int f[maxm][maxm];
        node()
        {
            memset(f,0x3f,sizeof(f));
        }
        void get(int u,int d)
        {
            for(int i=1;i<=m;++i)
            {
                for(int j=i,v=0;j<=m;++j,v+=v1[u][j-1]) f[i][j]=v;
                for(int j=i,v=0;j;--j,v+=v1[u][j]) f[i][j]=v;
                for(int j=1;j<=m;++j) f[i][j]+=v2[u][j];
                for(int k=u+1;k<=d;++k)
                {
                    for(int j=2;j<=m;++j) f[i][j]=min(f[i][j],f[i][j-1]+v1[k][j-1]);
                    for(int j=m-1;j;--j) f[i][j]=min(f[i][j],f[i][j+1]+v1[k][j]);
                    for(int j=1;j<=m;++j) f[i][j]+=v2[k][j];
                }
            }
        }
    }t[maxt];
    node operator +(const node &a,const node &b)
    {
        node c;
        memset(p,0,sizeof(p));
        for(int i=1;i<=m;++i)
            for(int j=m;j;--j)
                for(int k=(p[i-1][j]?p[i-1][j]:1);k<=(p[i][j+1]?p[i][j+1]:m);++k)
                    if(c.f[i][j]>a.f[i][k]+b.f[k][j])
                        c.f[i][j]=a.f[i][k]+b.f[k][j],p[i][j]=k;
        return c;
    }
    void build(int l,int r,int cur)
    {
        if(l==r)
        {
            t[cur].get(L[l],R[l]);
            return;
        }
        build(l,mid,ls),build(mid+1,r,rs),t[cur]=t[ls]+t[rs];
    }
    void update(int l,int r,int pos,int cur)
    {
        if(l==r)
        {
            t[cur].get(L[l],R[l]);
            return;
        }
        if(pos<=mid) update(l,mid,pos,ls);
        else update(mid+1,r,pos,rs);
        t[cur]=t[ls]+t[rs];
    }
    int main()
    {
        read(n),read(m);
        for(int i=1;i<=n;++i)
            for(int j=1;j<m;++j)
                read(v1[i][j]);
        for(int i=1;i<n;++i)
            for(int j=1;j<=m;++j)
                read(v2[i][j]);
        for(int i=1;i<=n;++i) bel[i]=(i-1)/S+1;
        for(int i=1;i<=bel[n];++i) L[i]=S*(i-1)+1,R[i]=S*i;
        R[bel[n]]=n,build(1,bel[n],root),read(q);
        while(q--)
        {
            int opt,x,y,v;
            read(opt),read(x),read(y),x++,y++;
            if(opt==1) read(v1[x][y]),update(1,bel[n],bel[x],root);
            if(opt==2) read(v2[x][y]),update(1,bel[n],bel[x],root);
            if(opt==3) printf("%d
    ",t[root].f[x][y]);
        }
        return 0;
    }
    
  • 相关阅读:
    js获取数组,对象的真实长度
    http和https区别
    react调用setstate后发生了什么
    for in for of foreach及map的区别
    事件委托(事件代理)
    CSS隐藏元素的几种方法
    react一些扩展
    [软件构造]异常的捕获与自定义
    [软件构造]可能是笔记总结吧
    计算机系统大作业
  • 原文地址:https://www.cnblogs.com/lhm-/p/13722391.html
Copyright © 2011-2022 走看看