2018CCPC網路賽-線段樹求區間最值+離散化+dp
阿新 • • 發佈:2018-12-13
原題目描述在最下面。 1e5個點,問從(0,0)走到(1e9,1e9)的最大收益。 當你從(u-1,v-1)走到(u,v)時,你可以獲得點(u,v)的權值。
solution:
十分詳細了。 直接線段樹區間最值。當然也可以樹狀陣列,不能st表。 dp[i]=max(query_max(0,dp[i]−1,1)+val[i],dp[i])dp[i]=max(query_max(0,dp[i]−1,1)+val[i],dp[i]) update(i,dp[i],1)update(i,dp[i],1) 記得離散化再排序,先x從小到大,再y從大到小,每次更行一行。 按01揹包的更新順序,滾動陣列優化為一維。 細節見程式碼。
#include<bits/stdc++.h> #define lson rt<<1 #define rson rt<<1|1 #define mme(a,b) memset((a),(b),sizeof((a))) using namespace std; typedef unsigned long long LL; const int N = 2e5 + 7; const int M = 1e5 + 7; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; int ar[N],br[N];//離散化 int dp[N]; struct lh //儲存1e5個點 { int x,y,v; } op[N]; bool cmp(lh &a,lh &b) { if(a.x!=b.x)return a.x<b.x; return a.y>b.y; } int n; /**********線段樹區間最值**********/ struct lp { int l, r, sum; } cw[N<<2]; void push_up(int rt) { cw[rt].sum = max(cw[lson].sum, cw[rson].sum); } void build(int l,int r,int rt) { cw[rt].l = l; cw[rt].r = r; cw[rt].sum = 0; if(l==r) { return; } int m = (l+r)/2; build(l,m,lson); build(m+1,r,rson); push_up(rt); } void update(int p,int c,int rt) { int l = cw[rt].l; int r = cw[rt].r; int m = (l+r)/2; if(l==r) { cw[rt].sum = c; return; } if(p<=m)update(p,c,lson); else update(p,c,rson); push_up(rt); } int query(int L,int R,int rt) { int l = cw[rt].l; int r = cw[rt].r; int m = (l+r)/2; if(L<=l&&r<=R) { return cw[rt].sum; } if(L>m)return query(L,R,rson); else if(R<=m)return query(L,R,lson); return max(query(L,m,lson),query(m+1,R,rson)); } /****************/ int main() { int T; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i = 0; i < n; ++i) { scanf("%d%d%d",&op[i].x,&op[i].y,&op[i].v); ar[i] = op[i].x; br[i]=op[i].y; } int p = n + 1; ar[n] = 0; br[n] = 0; sort(ar,ar+p); sort(br,br+p); int a = unique(ar,ar+p)-ar; int b = unique(br,br+p)-br; for(int i = 0; i < n; ++i) { op[i].x=lower_bound(ar,ar+a,op[i].x)-ar; op[i].y=lower_bound(br,br+b,op[i].y)-br; } //以上離散化 sort(op,op+n,cmp); build(0, b, 1); mme(dp, 0); for(int i = 0; i < n; ++i) { int flag = op[i].x, j; for(j = i; j < n; ++j) { if(op[j].x != flag) { break; } int tmp = query(0, op[j].y-1, 1) + op[j].v; if(tmp > dp[op[j].y]) { dp[op[j].y] = tmp; update(op[j].y, dp[op[j].y], 1); } } i = j - 1; } int ans = 0; for(int i = 0; i <= b; ++i) { ans = max(ans, dp[i]); } printf("%d\n", ans); } return 0; }