题目链接:

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<''||CH>'';F= CH=='-',CH=getchar());
for(num=;CH>=''&&CH<='';num=num*+CH-'',CH=getchar());
F && (num=-num);
}
int stk[], tp;
template<class T> inline void print(T p) {
if(!p) { puts(""); return; }
while(p) stk[++ tp] = p%, p/=;
while(tp) putchar(stk[tp--] + '');
putchar('\n');
} const LL mod=1e9+;
const double PI=acos(-1.0);
const LL inf=1e14;
const int N=1e5+; struct node
{
int l,r,dis;
};
vector<node>ve[N];
int cmp(node x,node y)
{
return x.dis<y.dis;
}
LL dp[][];
int a[][],le[N];
int n,m,p;
int main()
{
node x;
read(n);read(m);read(p);
for(int i=;i<=n;i++)
{
for(int j=;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=;i<=p;i++)
{
le[i]=ve[i].size();
}
for(int i=;i<le[];i++)
{
int l=ve[][i].l,r=ve[][i].r;
dp[l][r]=l+r-;
ve[][i].dis=dp[l][r];
}
sort(ve[].begin(),ve[].end(),cmp);
for(int i=;i<=p;i++)
{
int len1=le[i],len2=le[i-];
for(int j=;j<le[i];j++)
{
int l=ve[i][j].l,r=ve[i][j].r;
for(int k=;k<min(le[i-],);k++)
{
int fl=ve[i-][k].l,fr=ve[i-][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][].l,r=ve[p][].r;
print(dp[l][r]);
return ;
}
//二维线段树的代码
//#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+;
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<''||CH>'';F= CH=='-',CH=getchar());
for(num=;CH>=''&&CH<='';num=num*+CH-'',CH=getchar());
F && (num=-num);
}
int stk[], tp;
template<class T> inline void print(T p) {
if(!p) { puts(""); return; }
while(p) stk[++ tp] = p%, p/=;
while(tp) putchar(stk[tp--] + '');
putchar('\n');
} #define N 310
struct node{
int al,ar;
int mx;
};
struct node1{
int hl,hr;
node subt[];
}t[][N*];
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)>>;
build_sub(id,rt<<,ll,mid,flag);
build_sub(id,rt<<|,mid+,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,,ll,rr,flag);
if(l == r)return ;
int mid = (l+r)>>;
build(id<<,l,mid,ll,rr,flag);
build(id<<|,mid+,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)>>;
if(act<=mid)add_sub(id,rt<<,act,love,flag);
else add_sub(id,rt<<|,act,love,flag);
t[flag][id].subt[rt].mx = min(t[flag][id].subt[rt<<].mx, t[flag][id].subt[rt<<|].mx);
}
void add(int id,int h,int act,int love,int flag){
add_sub(id,,act,love,flag);
if(t[flag][id].hl == t[flag][id].hr){
return ;
}
int mid = (t[flag][id].hl+t[flag][id].hr)>>;
if(h<=mid)add(id<<,h,act,love,flag);
else add(id<<|,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)>>;
if(act<=mid)add_sub1(id,rt<<,act,love,flag);
else add_sub1(id,rt<<|,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,,act,love,flag);
if(t[flag][id].hl == t[flag][id].hr){
return ;
}
int mid = (t[flag][id].hl+t[flag][id].hr)>>;
if(h<=mid)add1(id<<,h,act,love,flag);
else add1(id<<|,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)>>;
if(rr<=mid)return sear(id,rt<<,ll,rr,flag);
else if(ll>mid)return sear(id,rt<<|,ll,rr,flag);
else return min(sear(id,rt<<,ll,mid,flag), sear(id,rt<<|,mid+,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,,ll,rr,flag);
}
int mid = (t[flag][id].hl+t[flag][id].hr)>>;
if(r<=mid)return query(id<<,l,r,ll,rr,flag);
else if(l>mid)return query(id<<|,l,r,ll,rr,flag);
else return min(query(id<<,l,mid,ll,rr,flag), query(id<<|,mid+,r,ll,rr,flag));
}
struct no
{
int l,r,dis;
};
vector<no>ve[N*N];
int a[][],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=;i<;i++)build(,,n,,m,i);
for(int i=;i<=p;i++)le[i]=ve[i].size();
for(int i=;i<le[];i++)
{
int l=ve[][i].l,r=ve[][i].r;
ve[][i].dis=l+r-;
} for(int i=;i<=p;i++)
{
int len1=le[i],len2=le[i-]; for(int j=;j<len2;j++)
{
int l=ve[i-][j].l,r=ve[i-][j].r;
add(,l,r,ve[i-][j].dis-l-r,);
add(,l,r,ve[i-][j].dis-l+r,);
add(,l,r,ve[i-][j].dis+l-r,);
add(,l,r,ve[i-][j].dis+l+r,);
}
for(int j=;j<len1;j++)
{
int l=ve[i][j].l,r=ve[i][j].r;
ve[i][j].dis=min(ve[i][j].dis,query(,,l,,r,)+l+r);
ve[i][j].dis=min(ve[i][j].dis,query(,,l,r,m,)+l-r);
ve[i][j].dis=min(ve[i][j].dis,query(,l,n,,r,)-l+r);
ve[i][j].dis=min(ve[i][j].dis,query(,l,n,r,m,)-l-r);
} for(int j=;j<len2;j++)
{
add1(,ve[i-][j].l,ve[i-][j].r,inf,);
add1(,ve[i-][j].l,ve[i-][j].r,inf,);
add1(,ve[i-][j].l,ve[i-][j].r,inf,);
add1(,ve[i-][j].l,ve[i-][j].r,inf,);
}
}
cout<<ve[p][].dis<<endl;
return ;
}

codeforces 677D D. Vanya and Treasure(二维线段树)的更多相关文章

  1. Codeforces 453E - Little Pony and Lord Tirek(二维线段树+ODT)

    Codeforces 题目传送门 & 洛谷题目传送门 一道难度 *3100 的 DS,而且被我自己搞出来了! 不过我终究还是技不如人,因为这是一个 \(n\log^2n\) + 大常数的辣鸡做 ...

  2. CodeForces 242E - XOR on Segment 二维线段树?

    今天练习赛的题....又是线段树的变换..拿到题我就敲了个点更新区间查询的..果断超时...然后想到了可以将每个数与合表示成不进位的二进制数..这样就可以区间进行更新了..比赛的时候写搓了..刚重写了 ...

  3. CodeForces 242E二维线段树

                                                                                           E. XOR on Seg ...

  4. 【Codeforces Round #433 (Div. 1) C】Boredom(二维线段树)

    [链接]我是链接 [题意] 接上一篇文章 [题解] 接(点我进入)上一篇文章. 这里讲一种用类似二维线段树的方法求矩形区域内点的个数的方法. 我们可以把n个正方形用n棵线段树来维护. 第i棵线段树维护 ...

  5. UVA 11297 线段树套线段树(二维线段树)

    题目大意: 就是在二维的空间内进行单个的修改,或者进行整块矩形区域的最大最小值查询 二维线段树树,要注意的是第一维上不是叶子形成的第二维线段树和叶子形成的第二维线段树要  不同的处理方式,非叶子形成的 ...

  6. POJ2155 Matrix二维线段树经典题

    题目链接 二维树状数组 #include<iostream> #include<math.h> #include<algorithm> #include<st ...

  7. HDU 1823 Luck and Love(二维线段树)

    之前只知道这个东西的大概概念,没具体去写,最近呵呵,今补上. 二维线段树 -- 点更段查 #include <cstdio> #include <cstring> #inclu ...

  8. poj 2155:Matrix(二维线段树,矩阵取反,好题)

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17880   Accepted: 6709 Descripti ...

  9. poj 1195:Mobile phones(二维线段树,矩阵求和)

    Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14391   Accepted: 6685 De ...

随机推荐

  1. 无责任Windows Azure SDK .NET开发入门篇三[使用Azure AD 管理用户信息--3.4 Edit修改用户信息]

    3.4 Edit修改用户信息 我们用FormCollection简化了表单提交,非常方便的进行用户信息修改. [HttpPost, Authorize] public async Task<Ac ...

  2. undefined index : HTTP_RAW_POST_DATA

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...

  3. uva387 - A Puzzling Problem

    A Puzzling Problem The goal of this problem is to write a program which will take from 1 to 5 puzzle ...

  4. MySQL中你肯定不知道的int隐情

    MySQL中定义id字段为int类型,但是你知道它内部是什么玩意吗? 1.如果定义int类型,但是不声明长度,系统默认为11个长度(这个大家都知道): 2.如果指定长度小于11,实际上系统还是默认为1 ...

  5. 连接SQLServer时提示“但是在登录前的握手期间发生错误。 (provider: SSL Provider, error: 0 - 等待的操作过时”解决办法

    解决:"已成功与服务器建立连接,但是在登录前的握手期间发生错误. (provider: SSL Provider, error: 0 - 等待的操作过时" 官方问题介绍:http: ...

  6. 线性回归(linear regression)之监督学习

    假设有以下面积和房屋价格的数据集: 可以在坐标中画出数据的情况: 就是基于这样一个数据集,假定给出一个房屋的面积,如何预测出它的价格?很显然就是我们只需建立一个关于房屋面积的函数,输出就是房屋的价格. ...

  7. HDU 5601 N*M bulbs 找规律

    N*M bulbs 题目连接: http://codeforces.com/contest/510/problem/C Description NM个灯泡排成一片,也就是排成一个NM的矩形,有些开着, ...

  8. Codeforces Round #136 (Div. 1)C. Little Elephant and Shifts multiset

    C. Little Elephant and Shifts Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/pro ...

  9. C# 如何编辑文件的摘要信息

    我的以前的测试报告程序需要在倒完测试数据报告后,在文件摘要中加上一些类似版权说明的文字等等. 因此需要对文件摘要信息进行编辑. 我的记忆中以前好像只有office文档才可以又摘要信息, 现在看来基本上 ...

  10. C#缩放和裁剪图片

    在GDI+中,缩放和剪裁可以看作同一个操作,无非就是原始区域的选择不同罢了.空口无凭,先看具体算法可能更好理解. using System; using System.Collections.Gene ...