zoukankan      html  css  js  c++  java
  • codeforces 677D D. Vanya and Treasure(二维线段树)

    题目链接:

    D. Vanya and Treasure

    time limit per test
    1.5 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Vanya is in the palace that can be represented as a grid n × m. Each room contains a single chest, an the room located in the i-th row and j-th columns contains the chest of type aij. Each chest of type x ≤ p - 1 contains a key that can open any chest of type x + 1, and all chests of type 1 are not locked. There is exactly one chest of type p and it contains a treasure.

    Vanya starts in cell (1, 1) (top left corner). What is the minimum total distance Vanya has to walk in order to get the treasure? Consider the distance between cell (r1, c1) (the cell in the row r1 and column c1) and (r2, c2) is equal to |r1 - r2| + |c1 - c2|.

     
    Input
     

    The first line of the input contains three integers nm and p (1 ≤ n, m ≤ 300, 1 ≤ p ≤ n·m) — the number of rows and columns in the table representing the palace and the number of different types of the chests, respectively.

    Each of the following n lines contains m integers aij (1 ≤ aij ≤ p) — the types of the chests in corresponding rooms. It's guaranteed that for each x from 1 to p there is at least one chest of this type (that is, there exists a pair of r and c, such that arc = x). Also, it's guaranteed that there is exactly one chest of type p.

     
    Output
     

    Print one integer — the minimum possible total distance Vanya has to walk in order to get the treasure from the chest of type p.

     
    Examples
     
    input
    3 4 3
    2 1 1 1
    1 1 1 1
    2 1 1 3
    output
    5
    input
    3 3 9
    1 3 5
    8 9 7
    4 6 2
    output
    22
    input
    3 4 12
    1 2 3 4
    8 7 6 5
    9 10 11 12
    output
    11


    题意:


    每次从(1,1)出发,最终要到达a[i][j]==p的位置,每次只能从a[i][j]==x的位置到达任意一个a[i][j]==x+1的位置,行走的距离为abs(r1-r2)+abs(c1-c2);
    问最后到达终点最少的距离是多少;

    思路:

    第一个代码是水过去的;
    第二个是用二维线段树过得;
    dp[i][j]=min(dp[i][j],dp[pi][pj]+abs(i-pi)+abs(j-pj));a[pi][pj]+1=a[i][j];
    去掉绝对值可以得到这样4个式子:
    if(pi>=i&&pj>=j)dp[i][j]=min(dp[i][j],dp[pi][pj]+pi+pj-(i+j));
    if(pi>=i&&pj<=j)dp[i][j]=min(dp[i][j],dp[pi][pj]+pi-pj-(i-j));
    if(pi<=i&&pj>=j)dp[i][j]=min(dp[i][j],dp[pi][pj]+pj-pi-(j-i));
    if(pi<=i&&pj<=j)dp[i][j]=min(dp[i][j],dp[pi][pj]-(pi+pj)+(i+j));(ps:等号没影响)

    每次把dp[pi][pj]+(后面pi和pj)这个式子的值插入二维线段树,每次的询问根据pi,pj,i,j的大小关系就是四个矩形区域,维护最小值就行;
    最慢的一组数据跑了1300+ms;感觉要是把暴力加里面去有一些数据的时间可能会短一点;

    感觉我这种看不懂别人题解的智障只能想这种超级麻烦的方法;

    AC代码:

    #include <bits/stdc++.h>
    /*#include <vector>
    #include <iostream>
    #include <queue>
    #include <cmath>
    #include <map>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    */
    using namespace std;
    #define Riep(n) for(int i=1;i<=n;i++)
    #define Riop(n) for(int i=0;i<n;i++)
    #define Rjep(n) for(int j=1;j<=n;j++)
    #define Rjop(n) for(int j=0;j<n;j++)
    #define mst(ss,b) memset(ss,b,sizeof(ss));
    typedef long long LL;
    template<class T> void read(T&num) {
        char CH; bool F=false;
        for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
        for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
        F && (num=-num);
    }
    int stk[70], tp;
    template<class T> inline void print(T p) {
        if(!p) { puts("0"); return; }
        while(p) stk[++ tp] = p%10, p/=10;
        while(tp) putchar(stk[tp--] + '0');
        putchar('
    ');
    }
    
    const LL mod=1e9+7;
    const double PI=acos(-1.0);
    const LL inf=1e14;
    const int N=1e5+15;
    
    struct node
    {
        int l,r,dis;
    };
    vector<node>ve[N];
    int cmp(node x,node y)
    {
        return x.dis<y.dis;
    }
    LL dp[305][305];
    int a[305][305],le[N];
    int n,m,p;
    int main()
    {
        node x;
        read(n);read(m);read(p);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                dp[i][j]=inf;
        }
        Riep(n)
        {
            Rjep(m)
            {
                read(a[i][j]);
                x.l=i;
                x.r=j;
                ve[a[i][j]].push_back(x);
            }
        }
        for(int i=1;i<=p;i++)
        {
            le[i]=ve[i].size();
        }
        for(int i=0;i<le[1];i++)
        {
            int l=ve[1][i].l,r=ve[1][i].r;
            dp[l][r]=l+r-2;
            ve[1][i].dis=dp[l][r];
        }
        sort(ve[1].begin(),ve[1].end(),cmp);
        for(int i=2;i<=p;i++)
        {
            int len1=le[i],len2=le[i-1];
            for(int j=0;j<le[i];j++)
            {
                int l=ve[i][j].l,r=ve[i][j].r;
                for(int k=0;k<min(le[i-1],4000);k++)
                {
                    int fl=ve[i-1][k].l,fr=ve[i-1][k].r;
                    if(dp[fl][fr]>=dp[l][r])break;
                    dp[l][r]=min(dp[l][r],dp[fl][fr]+abs(fl-l)+abs(fr-r));
                }
                ve[i][j].dis=dp[l][r];
            }
            sort(ve[i].begin(),ve[i].end(),cmp);
        }
            int l=ve[p][0].l,r=ve[p][0].r;
        print(dp[l][r]);
        return 0;
    }
    //二维线段树的代码
    //#include <bits/stdc++.h>
    
    #include <iostream>
    #include <queue>
    #include <cmath>
    #include <map>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    #define Riep(n) for(int i=1;i<=n;i++)
    #define Riop(n) for(int i=0;i<n;i++)
    #define Rjep(n) for(int j=1;j<=n;j++)
    #define Rjop(n) for(int j=0;j<n;j++)
    #define mst(ss,b) memset(ss,b,sizeof(ss));
    typedef long long LL;
    const LL mod=1e9+7;
    const double PI=acos(-1.0);
    const int inf=0x3f3f3f3f;
    
    template<class T> void read(T&num) {
        char CH; bool F=false;
        for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
        for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
        F && (num=-num);
    }
    int stk[70], tp;
    template<class T> inline void print(T p) {
        if(!p) { puts("0"); return; }
        while(p) stk[++ tp] = p%10, p/=10;
        while(tp) putchar(stk[tp--] + '0');
        putchar('
    ');
    }
    
    #define N 310
    struct node{
        int al,ar;
        int mx;
    };
    struct node1{
        int hl,hr;
        node subt[4000];
    }t[4][N*4];
    void build_sub(int id,int rt,int ll,int rr,int flag){
        t[flag][id].subt[rt].al = ll;
        t[flag][id].subt[rt].ar = rr;
        t[flag][id].subt[rt].mx = inf;
        if(ll == rr){
            return ;
        }
        int mid = (ll+rr)>>1;
        build_sub(id,rt<<1,ll,mid,flag);
        build_sub(id,rt<<1|1,mid+1,rr,flag);
    }
    void build(int id,int l,int r,int ll,int rr,int flag){
        t[flag][id].hl = l;
        t[flag][id].hr = r;
        build_sub(id,1,ll,rr,flag);
        if(l == r)return ;
        int mid = (l+r)>>1;
        build(id<<1,l,mid,ll,rr,flag);
        build(id<<1|1,mid+1,r,ll,rr,flag);
    }
    void add_sub(int id,int rt,int act,int love,int flag){
        t[flag][id].subt[rt].mx = min(love,t[flag][id].subt[rt].mx);
        if(t[flag][id].subt[rt].al == t[flag][id].subt[rt].ar)return ;
        int mid = (t[flag][id].subt[rt].al+t[flag][id].subt[rt].ar)>>1;
        if(act<=mid)add_sub(id,rt<<1,act,love,flag);
        else add_sub(id,rt<<1|1,act,love,flag);
        t[flag][id].subt[rt].mx = min(t[flag][id].subt[rt<<1].mx, t[flag][id].subt[rt<<1|1].mx);
    }
    void add(int id,int h,int act,int love,int flag){
        add_sub(id,1,act,love,flag);
        if(t[flag][id].hl ==  t[flag][id].hr){
            return ;
        }
        int mid = (t[flag][id].hl+t[flag][id].hr)>>1;
        if(h<=mid)add(id<<1,h,act,love,flag);
        else add(id<<1|1,h,act,love,flag);
    }
    void add_sub1(int id,int rt,int act,int love,int flag){
        t[flag][id].subt[rt].mx = love;
        if(t[flag][id].subt[rt].al == t[flag][id].subt[rt].ar)return ;
        int mid = (t[flag][id].subt[rt].al+t[flag][id].subt[rt].ar)>>1;
        if(act<=mid)add_sub1(id,rt<<1,act,love,flag);
        else add_sub1(id,rt<<1|1,act,love,flag);
        t[flag][id].subt[rt].mx = love;
    }
    void add1(int id,int h,int act,int love,int flag){
        add_sub1(id,1,act,love,flag);
        if(t[flag][id].hl ==  t[flag][id].hr){
            return ;
        }
        int mid = (t[flag][id].hl+t[flag][id].hr)>>1;
        if(h<=mid)add1(id<<1,h,act,love,flag);
        else add1(id<<1|1,h,act,love,flag);
    }
    int sear(int id,int rt,int ll,int rr,int flag){
        if(t[flag][id].subt[rt].al==ll && t[flag][id].subt[rt].ar==rr){
            return t[flag][id].subt[rt].mx;
        }
        int mid = (t[flag][id].subt[rt].al+t[flag][id].subt[rt].ar)>>1;
        if(rr<=mid)return sear(id,rt<<1,ll,rr,flag);
        else if(ll>mid)return sear(id,rt<<1|1,ll,rr,flag);
        else return min(sear(id,rt<<1,ll,mid,flag), sear(id,rt<<1|1,mid+1,rr,flag));
    }
    int query(int id,int l,int r,int ll,int rr,int flag){
        if(t[flag][id].hl==l && t[flag][id].hr==r){
            return sear(id,1,ll,rr,flag);
        }
        int mid = (t[flag][id].hl+t[flag][id].hr)>>1;
        if(r<=mid)return query(id<<1,l,r,ll,rr,flag);
        else if(l>mid)return query(id<<1|1,l,r,ll,rr,flag);
        else return min(query(id<<1,l,mid,ll,rr,flag), query(id<<1|1,mid+1,r,ll,rr,flag));
    }
    struct no
    {
        int l,r,dis;
    };
    vector<no>ve[N*N];
    int a[305][305],le[N*N];
    int n,m,p;
    int main()
    {
    
        no x;
        read(n);read(m);read(p);
        Riep(n)
        {
            Rjep(m)
            {
                read(a[i][j]);
                x.l=i;
                x.r=j;
                x.dis=inf;
                ve[a[i][j]].push_back(x);
            }
        }
        for(int i=0;i<4;i++)build(1,1,n,1,m,i);
        for(int i=1;i<=p;i++)le[i]=ve[i].size();
        for(int i=0;i<le[1];i++)
        {
            int l=ve[1][i].l,r=ve[1][i].r;
            ve[1][i].dis=l+r-2;
        }
        
        for(int i=2;i<=p;i++)
        {
            int len1=le[i],len2=le[i-1];
    
            for(int j=0;j<len2;j++)
            {
                int l=ve[i-1][j].l,r=ve[i-1][j].r;
                add(1,l,r,ve[i-1][j].dis-l-r,0);
                add(1,l,r,ve[i-1][j].dis-l+r,1);
                add(1,l,r,ve[i-1][j].dis+l-r,2);
                add(1,l,r,ve[i-1][j].dis+l+r,3);
            }
            for(int j=0;j<len1;j++)
            {
                int l=ve[i][j].l,r=ve[i][j].r;
                ve[i][j].dis=min(ve[i][j].dis,query(1,1,l,1,r,0)+l+r);
                ve[i][j].dis=min(ve[i][j].dis,query(1,1,l,r,m,1)+l-r);
                ve[i][j].dis=min(ve[i][j].dis,query(1,l,n,1,r,2)-l+r);
                ve[i][j].dis=min(ve[i][j].dis,query(1,l,n,r,m,3)-l-r);
            }
    
            for(int j=0;j<len2;j++)
            {
                add1(1,ve[i-1][j].l,ve[i-1][j].r,inf,0);
                add1(1,ve[i-1][j].l,ve[i-1][j].r,inf,1);
                add1(1,ve[i-1][j].l,ve[i-1][j].r,inf,2);
                add1(1,ve[i-1][j].l,ve[i-1][j].r,inf,3);
            }
        }
        cout<<ve[p][0].dis<<endl;
        return 0;
    }



  • 相关阅读:
    由博客园页面样式挖出的一款心机软件
    SQL Server 各任务所维护
    [转载]SQL Server查找包含某关键字的存储过程3种方法
    Hibernate简单注解开发和事务处理(四)
    Hibernate实现简单的CRUD操作和常见类(三)
    Hibernate中hibernate.cfg.xml文件和Xxx.hbm.xml文件的详细解释(二)
    Hibernate开发环境的简单搭建及常见错误(一)
    Struts2配置异常错误处理(十六)
    Struts2实现类型转换器(十五)
    Struts2实现JSON和Ajax操作(十四)
  • 原文地址:https://www.cnblogs.com/zhangchengc919/p/5552651.html
Copyright © 2011-2022 走看看