Snowy Smile HDU - 6638(扫描线,线段树区间合并)

2024-04-15 23:38

本文主要是介绍Snowy Smile HDU - 6638(扫描线,线段树区间合并),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

There are n pirate chests buried in Byteland, labeled by 1,2,…,n. The i-th chest’s location is (xi,yi), and its value is wi, wi can be negative since the pirate can add some poisonous gases into the chest. When you open the i-th pirate chest, you will get wi value.

You want to make money from these pirate chests. You can select a rectangle, the sides of which are all paralleled to the axes, and then all the chests inside it or on its border will be opened. Note that you must open all the chests within that range regardless of their values are positive or negative. But you can choose a rectangle with nothing in it to get a zero sum.

Please write a program to find the best rectangle with maximum total value.
Input
The first line of the input contains an integer T(1≤T≤100), denoting the number of test cases.

In each test case, there is one integer n(1≤n≤2000) in the first line, denoting the number of pirate chests.

For the next n lines, each line contains three integers xi,yi,wi(−109≤xi,yi,wi≤109), denoting each pirate chest.

It is guaranteed that ∑n≤10000.
Output
For each test case, print a single line containing an integer, denoting the maximum total value.
Sample Input
2
4
1 1 50
2 1 50
1 2 50
2 2 -500
2
-1 1 5
-1 1 1
Sample Output
100
6

题意:
平面上很多个带权点,求一个矩阵覆盖一些点使得权值和最大。

思路:
n n n的范围只有2000,所以可以枚举矩阵的下边界( y y y轴)。然后每次将矩阵上边界移动一个单位(离散化后的单位)。线段树维护每个点在 x x x轴上的位置,维护一下最大值,就得到了当前的最大权值矩阵。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>using namespace std;typedef long long ll;
const int maxn = 4e3 + 7;
struct Node {int x,y,w;
}a[maxn];
vector<pair<int,int> >vec[maxn];struct Tree {int l,r;ll sum;ll mx,lmx,rmx;
}t[maxn << 2];void pushup(int i) {t[i].mx = max(max(t[i * 2].mx,t[i * 2 + 1].mx),t[i * 2].rmx + t[i * 2 + 1].lmx);t[i].sum = t[i * 2].sum + t[i * 2 + 1].sum;t[i].lmx = max(t[i * 2].lmx,t[i * 2].sum + t[i * 2 + 1].lmx);t[i].rmx = max(t[i * 2 + 1].rmx,t[i * 2 + 1].sum + t[i * 2].rmx);
}void build(int i,int l,int r) {t[i].l = l;t[i].r = r;if(l == r) {t[i].sum = t[i].mx = t[i].lmx = t[i].rmx = 0;return;}int m = (l + r) >> 1;build(i * 2,l,m);build(i * 2 + 1,m + 1,r);pushup(i);
}void update(int i,int x,int v) {if(t[i].l == t[i].r) {t[i].sum += v;t[i].lmx += v;t[i].rmx += v;t[i].mx += v;return;}int m = (t[i].l + t[i].r) >> 1;if(x <= m) update(i * 2,x,v);if(x > m)  update(i * 2 + 1,x,v);pushup(i);
}int main() {int T;scanf("%d",&T);while(T--) {int n;scanf("%d",&n);vector<int>vecx,vecy;for(int i = 1;i <= n;i++) {scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);vecx.push_back(a[i].x);vecy.push_back(a[i].y);vec[i].clear();}sort(vecx.begin(),vecx.end());sort(vecy.begin(),vecy.end());vecx.erase(unique(vecx.begin(),vecx.end()),vecx.end());vecy.erase(unique(vecy.begin(),vecy.end()),vecy.end());for(int i = 1;i <= n;i++) {a[i].x = lower_bound(vecx.begin(),vecx.end(),a[i].x) - vecx.begin() + 1;a[i].y = lower_bound(vecy.begin(),vecy.end(),a[i].y) - vecy.begin() + 1;vec[a[i].y].push_back({a[i].x,a[i].w});}ll ans = 0;for(int i = 1;i <= vecy.size();i++) { //矩阵下界build(1,1,vecy.size());for(int j = i;j <= vecy.size();j++) { //矩阵上界for(int k = 0;k < vec[j].size();k++) {int pos = vec[j][k].first,val = vec[j][k].second;update(1,pos,val);}ans = max(ans,t[1].mx);}}printf("%lld\n",ans);}return 0;
}

这篇关于Snowy Smile HDU - 6638(扫描线,线段树区间合并)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/907245

相关文章

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while