这题是一个游戏题,名曰:是男人就下一百层。就是给定一系列的坐标,首先是纵坐标,然后是线段的左右坐标,最后是在该条线段的增加或者扣除的血量。
解决这题的关键在于如何处理这多条线段的关系,如果是从上而下的话,那么我们能够更新一条边的两个端点下的最优值,那么对于后面加入的边就有下面的动态方程:
sum[f] = max( sum(x), f.x1 <= x <= f.x2 ) + val(f) 需要在该边的区域内寻找最大值来更新这条边的两个端点值,这样做显然处理起来较麻烦,时间开销也比较大。所以我们应该从下面开始往上面更新,对于最下面的一条边我们能够更新该条边的最优值,而对于上面的边,我们只要查找其左右两个端点的最优值来更新该条边即可。 sum[f] = max( sum(x1), sum(x2) ) + val(f)代码如下:
#include#include #include #include #define MAXN 100000 using namespace std; struct { int l, r, val, cover; }seg[MAXN*3]; struct Node { int x1, x2, y, val; bool operator < (Node t) const { return y < t.y; } }e[MAXN]; void creat(int f, int l, int r) { int mid = (l+r)>>1; seg[f].l = l, seg[f].r = r; seg[f].val = 0, seg[f].cover = 0; if (r > l) { creat(f<<1, l, mid); creat(f<<1|1, mid+1, r); } } void init() { creat(1, 1, MAXN); seg[1].cover = 1, seg[1].val = 100; } int query(int f, int pos) { int mid = (seg[f].l+seg[f].r)>>1; if (seg[f].cover == 1) { return seg[f].val; } if (pos <= mid) return query(f<<1, pos); else return query(f<<1|1, pos); } void modify(int f, int l, int r, int val) { int mid = (seg[f].l+seg[f].r)>>1; if (seg[f].l == l && r == seg[f].r) { seg[f].val = val; seg[f].cover = 1; } else if (seg[f].r > seg[f].l) { if (seg[f].cover == 1) { seg[f<<1].cover = seg[f<<1|1].cover = 1; seg[f<<1].val = seg[f<<1|1].val = seg[f].val; seg[f].cover = 0; } if (r <= mid) modify(f<<1, l, r, val); else if (l > mid) modify(f<<1|1, l, r, val); else { modify(f<<1, l, mid, val); modify(f<<1|1, mid+1, r, val); } } } int main() { int N, x; while (scanf("%d", &N) == 1) { for (int i = 0; i < N; ++i) { scanf("%d %d %d %d", &e[i].y, &e[i].x1, &e[i].x2, &e[i].val); } sort(e, e+N); init(); for (int i = 0; i < N; ++i) { x = max(query(1, e[i].x1), query(1, e[i].x2)); modify(1, e[i].x1, e[i].x2, x+e[i].val); } x = max(query(1, e[N-1].x1), query(1, e[N-1].x2)); printf(x >= 0 ? "%d\n" : "-1\n", x); } return 0; }