1. 程式人生 > >【BZOJ】1537: [POI2005]Aut- The Bus

【BZOJ】1537: [POI2005]Aut- The Bus

spl read zoj return 觀察 cst isp algo ins

【算法】DP+線段樹求區間max(二維偏序)

【題解】

狀態轉移方程:f[i]=max(f[j]+v[i]),x[j]<x[i]&&y[j]<y[i]。

觀察j的條件限制顯然是二維偏序求最大值,套路化地離散化後一維排序+一維線段樹即可解決。

最後在f[i]中找max,所以不用恢復原序。

復雜度O(n log n)。

技術分享
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
const int
maxn=300010; int f[maxn],n,m,k; inline int max(int x,int y){return x>y?x:y;} struct lshs{int x,ord;}ls[maxn]; struct cyc{int x,y,v;}a[maxn]; struct tree{int l,r,mx;}t[maxn*2]; bool cmps(cyc a,cyc b){return a.x<b.x||(a.x==b.x&&a.y<b.y);} bool cmp(lshs a,lshs b){return a.x<b.x;} int read() {
char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c==-)t=-1; do{s=s*10+c-0;}while(isdigit(c=getchar())); return s*t; } void lsh(){ for(int i=1;i<=k;i++)ls[i]=(lshs){a[i].x,i}; sort(ls+1,ls+k+1,cmp); int p=0; for(int i=1;i<=k;i++)if(ls[i].x==ls[i-1].x)a[ls[i].ord].x=p;else
a[ls[i].ord].x=++p; n=p; for(int i=1;i<=k;i++)ls[i]=(lshs){a[i].y,i}; sort(ls+1,ls+k+1,cmp); p=0; for(int i=1;i<=k;i++)if(ls[i].x==ls[i-1].x)a[ls[i].ord].y=p;else a[ls[i].ord].y=++p; m=p; } void build(int k,int l,int r){ t[k].l=l;t[k].r=r; if(l==r)return; int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void insert(int k,int x,int y){ if(t[k].l==t[k].r){t[k].mx=max(t[k].mx,y);} else{ int mid=(t[k].l+t[k].r)>>1; if(x<=mid)insert(k<<1,x,y); else insert(k<<1|1,x,y); t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx); } } int find(int k,int l,int r){ if(l<=t[k].l&&t[k].r<=r)return t[k].mx; else{ int mid=(t[k].l+t[k].r)>>1,mx=0; if(l<=mid)mx=find(k<<1,l,r); if(r>mid)mx=max(mx,find(k<<1|1,l,r)); return mx; } } int main(){ n=read();m=read();k=read(); for(int i=1;i<=k;i++){ a[i].x=read();a[i].y=read();a[i].v=read(); } lsh(); sort(a+1,a+k+1,cmps); build(1,1,m); for(int i=1;i<=k;i++){ f[i]=find(1,1,a[i].y)+a[i].v; insert(1,a[i].y,f[i]); } int ans=0; for(int i=1;i<=k;i++)ans=max(ans,f[i]); printf("%d",ans); return 0; }
View Code

【BZOJ】1537: [POI2005]Aut- The Bus