链接
http://acm.hdu.edu.cn/showproblem.php?pid=6447
题意
网格上面有一些村庄 村庄里面有钱
你只能向右、向下、或者向右下走
从a->b,只有当 Xa<Xb && Ya<Yb时候才能获得b点的钱
你一开始在(0,0)
问你最多能获得多少钱
思路
现将y排序 离散化成一段连续的区间
然后将x排序 当成时间 然后按x的大小处理问题
y离散化之后用线段树存储
dp[i]表示到纵坐标i的点能得到的最大值
dp[i]=max(dp[1..i-1])+val
用线段树维护dp[i],优化求最大值的时间
上代码
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
const int M=100050;
const int MM=200100;
int n;
int a[M],b[M],val[M],d[M],e[MM],f[MM],dp[MM];
int pxb(int l,int r)
{
int i=l,j=r,m=b[(l+r)/2],t;
do
{
while (b[i]<m) i++;
while (b[j]>m) j--;
if (i<=j)
{
t=a[i]; a[i]=a[j]; a[j]=t;
t=b[i]; b[i]=b[j]; b[j]=t;
t=val[i]; val[i]=val[j]; val[j]=t;
i++; j--;
}
}
while (i<=j);
if (i<r) pxb(i,r);
if (l<j) pxb(l,j);
}
int pxa(int l,int r)
{
int i=l,j=r,m=a[(l+r)/2],t;
do
{
while (a[i]<m) i++;
while (a[j]>m) j--;
if (i<=j)
{
t=a[i]; a[i]=a[j]; a[j]=t;
t=b[i]; b[i]=b[j]; b[j]=t;
t=val[i]; val[i]=val[j]; val[j]=t;
t=d[i]; d[i]=d[j]; d[j]=t;
i++; j--;
}
}
while (i<=j);
if (i<r) pxa(i,r);
if (l<j) pxa(l,j);
}
int weihu(int l,int r,int p,int w,int z)
{
if (l==r)
{
e[l]=max(z,e[l]);
return e[l];
}
int m=(l+r)/2,t;
if (w<=m)
{
t=weihu(l,m,p*2,w,z);
f[p]=max(t,f[p]);
} else
{
t=weihu(m+1,r,p*2+1,w,z);
f[p]=max(t,f[p]);
}
return f[p];
}
int work(int l,int r,int p,int w)
{
if (l==r) return e[l];
if (r<=w) return f[p];
int m=(l+r)/2,t;
if (w<=m)
{
t=work(l,m,p*2,w);
} else
{
t=max(work(l,m,p*2,w),work(m+1,r,p*2+1,w));
}
return t;
}
int main()
{
int cas;
scanf("%d",&cas);
for (int ii=1;ii<=cas;ii++)
{
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d%d%d",&a[i],&b[i],&val[i]);
pxb(1,n); // 按b排序 为了离散化 将其压成一段连续的区间
int k=1;
b[0]=0;
for (int i=1;i<=n;i++)
{
if (b[i]>b[i-1]) k++;
d[i]=k;
}
pxa(1,n); // 按横坐标排序
a[n+1]=-1;
for (int i=0;i<=2*(k+1);i++) f[i]=0,e[i]=0,dp[i]=0;
int h=1,t;
while (h<=n)
{
t=h;
while (a[t+1]==a[t]) t++; // 舍弃掉横坐标相同的
for (int i=h;i<=t;i++)
{
if (a[i]==0 || b[i]==0) continue;
dp[i]=work(1,n,1,d[i]-1)+val[i];
}
for (int i=h;i<=t;i++)
{
if (a[i]==0 || b[i]==0) continue;
weihu(1,n,1,d[i],dp[i]);
}
h=t+1;
}
printf("%d\n",f[1]);
}
return 0;
}
// 这代码是捞毛的,感觉略怪 有空自己写一个