离散化+DP+树状数组P3431【The Bus】
greenheadstrange · · 题解
很容易想到O(nm)的DP但是一看m和n的范围10^9,GG
再一看k的范围10^5,便想到离散化一下
//本蒟蒻是用map来离散化的,但是推荐dalao们还是用lower_bound比较好
map<int,int>mpx,mpy;
for(int i=1;i<=k;i++){
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].s);
x[i]=a[i].x;
y[i]=a[i].y;
}
x[0]=y[0]=1;
sort(x,x+k+1);
sort(y,y+k+1);
mpx[x[0]]=++nx;
mpy[y[0]]=++ny;
for(int i=1;i<=k;i++){
if(x[i]!=x[i-1])mpx[x[i]]=++nx;
if(y[i]!=y[i-1])mpy[y[i]]=++ny;
}
for(int i=1;i<=k;i++)a[i].x=mpx[a[i].x],a[i].y=mpy[a[i].y];
此时的复杂度瞬间降到了O(k^2)但是只有40分,怎么办?
不要慌,先将动态转移方程写出来看看^_^
设f[i]表示走到点i的最大值
将数组a以横坐标作为第一关键字,纵坐标作为第二关键字排序后
f[i]=max(f[j])+a[i].s(其间a[j].y<=a[i].y)
亲爱的童鞋们,看到这里是不是想到了什么优化?
树状数组
sort(a+1,a+k+1,cmp);
for(int i=1;i<=k;i++){
f[i]=ask(a[i].y)+a[i].s;
modify(a[i].y,f[i]);
}
下面是本蒟蒻的丑代码:
#include<bits/stdc++.h>
using namespace std;
const int A=500005;
map<int,int>mpx,mpy;
struct note{
int x,y,s;
}a[A];
int n,m,k,ans,x[A],y[A],c[A*4],f[A],nx,ny;
bool cmp(const note&aa,const note&bb){//以横坐标作为第一关键字,纵坐标作为第二关键字排序
return (aa.x==bb.x?aa.y<bb.y:aa.x<bb.x);
}
///////////////////////////////树状数组
int lowbit(int x){return x&(-x);}//lowbit操作
void modify(int x,int k){//单点修改
for(int i=x;i<=ny;i+=lowbit(i))c[i]=max(c[i],k);
}
int ask(int x){//区间查询
int maxx=0;
for(int i=x;i;i-=lowbit(i))maxx=max(maxx,c[i]);
return maxx;
}
///////////////////////////////
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++){
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].s);
x[i]=a[i].x;
y[i]=a[i].y;
}
///////////////////////////////离散化
x[0]=y[0]=1;
sort(x,x+k+1);
sort(y,y+k+1);
mpx[x[0]]=++nx;
mpy[y[0]]=++ny;
for(int i=1;i<=k;i++){
if(x[i]!=x[i-1])mpx[x[i]]=++nx;
if(y[i]!=y[i-1])mpy[y[i]]=++ny;
}
for(int i=1;i<=k;i++)a[i].x=mpx[a[i].x],a[i].y=mpy[a[i].y];
///////////////////////////////
///////////////////////////////DP
sort(a+1,a+k+1,cmp);
for(int i=1;i<=k;i++){
f[i]=ask(a[i].y)+a[i].s;
modify(a[i].y,f[i]);
}
for(int i=1;i<=k;i++)ans=max(ans,f[i]);
///////////////////////////////
printf("%d",ans);
return 0;
}
结束语:这道题并不难DP+树状数组,但是本蒟蒻却毒瘤了一个小时,结果是粗心将k与n混用了,在此,本蒟蒻提醒您:
代码千万条,细心第一条。
代码不规范,毒瘤两行泪。