免費的餡餅(二維偏序)(樹狀陣列版)
阿新 • • 發佈:2018-11-08
https://vjudge.net/contest/261263#problem/B(題目連結)
因為一秒可以走1或2步或不走。
我們可以看成半秒走1步或不走。
dp[i]表示接到第i塊餅時最大的分數值
現在有兩塊餅它們下落的時間為ti,tj,位置為pi,pj;
假設ti > tj;
只有ti - tj >= |pi - pj| 時dp[j]可以轉移到dp[i];
當pi > pj 時 ti -tj > pi - pj
ti - pi > tj - pj;
當pi < pj 時 ti -tj > pj - pi
ti + pi > tj + pj;
當pi > pj , ti -tj > pi - pj時 pj - pi < 0 , ti - tj > pj - pi;
當pi < pj , ti -tj > pj - pi時 pi - pj<0, ti -tj > pi - pj ;
所以dp[j]可以轉移到dp[i]的條件是
ti + pi > tj + pj;並且ti - pi > tj - pj;
這是個二維偏序問題
我們把v1 看成 ti + pi, 把v2看成ti - pi
把v1看成第一維從小到大排序,v2 看成第二維用資料結構維護
先把v2離散化
在把所有餅按v1從小到大排序,再在以離散化後的v2為下標,dp為值的一棵值域線段樹(我寫的樹狀陣列)上找能更新到這個點的最大的dp值。
樹狀陣列維護區間最大值,支援修改和查詢操作
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int w, n, sval[100005], ans, f[100005], dp[100005]; struct node { int v1, v2, val; }; node q[100005]; bool cmp(const node a,const node b) { return a.v1 < b.v1; } int qurey(int a) { int rt = 0; for(int i = a; i; i -= i &(-i)) { rt = max(rt,f[i]); } return rt; } void modify(int a,int b) { for(int i = a; i <= n; i += i&(-i)) { f[i] = max(f[i],b); } } int main() { cin >> w >> n; for(int i = 1; i <= n; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); q[i].v1 = a * 2 + b; q[i].v2 = a * 2 - b; sval[i] = q[i].v2; q[i].val = c; } sort(sval+1,sval+1+n); int m = unique(sval+1,sval+1+n) - sval; for(int i = 1; i <= n; i++) { q[i].v2 = lower_bound(sval+1,sval+1+m,q[i].v2) - sval; } sort(q+1,q+1+n,cmp); for(int i = 1; i <= n; i++) { int ha = qurey(q[i].v2); dp[i] = ha + q[i].val; modify(q[i].v2,dp[i]); } for(int i = 1; i <= n; i++) ans = max(dp[i],ans); cout << ans << endl; return 0; }