풀이
이 문제와 비슷하게 분할정복으로 접근한다.
x축을 기준으로 정렬해서, 모든 [l, r]
구간에서 최댓값을 하나씩 찾을 것이다.
시작점을 하나 정해놓고, 끝점까지 스위핑 하면서 최댓값을 찾아 주자.
스위핑이 하나 전진할 때마다 분할정복 트리를 업데이트 해 주면 된다.
이러한 구간이 많아야 3000^2
개이므로 여기에 로그 붙여도 충분하다.
세그트리 업데이트 하는 느낌으로 분할정복을 하면 된다.
나는 멍청하게 구간합 업데이트를 펜윅트리 써서 했는데 여러분들은 그러지 말자. ㅋㅋㅋㅋ
까다로운 반례가 있으므로 주의하자.
코드
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const ll INF = 1e14;
const int MAXN = (1<<12);
int n;
struct abc {
int x, y; ll w;
bool operator <(abc &a)const {
if (x == a.x) return y < a.y;
return x < a.x;
}
} a[MAXN+5];
ll t[MAXN+5];
struct node {
int s, e;
ll mmax, lmax, rmax;
} tree[MAXN*4+5];
void t_udpate(int i, ll x) { // point update
for (; i<=n; i+=i&-i) t[i]+=x;
}
ll t_query(int s, int e) { // range sum [s, e]
ll r1 = 0, r2 = 0;
for (; e; e-=e&-e) r1+=t[e];
for (--s; s; s-=s&-s) r2+=t[s];
return r1-r2;
}
void update(int now) {
int idx = a[now].y+MAXN-1;
t_udpate(a[now].y, a[now].w);
ll tmp = (tree[idx].mmax == -INF ? INF+a[now].w : a[now].w);
tree[idx].mmax += tmp;
tree[idx].lmax += tmp;
tree[idx].rmax += tmp;
idx /= 2;
while (idx) {
auto &l = tree[idx*2], &r = tree[idx*2+1], &m = tree[idx];
m.mmax = max({ l.mmax, r.mmax, l.lmax+r.rmax });
m.lmax = max(r.lmax, l.lmax+t_query(r.s, r.e));
m.rmax = max(l.rmax, r.rmax+t_query(l.s, l.e));
idx /= 2;
}
}
int main() {
scanf("%d", &n);
vector<int> vx, vy;
for (int i = 1; i <= n; i++) {
scanf("%d %d %lld", &a[i].x, &a[i].y, &a[i].w);
vx.push_back(a[i].x); vy.push_back(a[i].y);
}
sort(vx.begin(), vx.end());
sort(vy.begin(), vy.end());
for (int i = 1; i <= n; i++) {
a[i].x = lower_bound(vx.begin(), vx.end(), a[i].x)-vx.begin()+1;
a[i].y = lower_bound(vy.begin(), vy.end(), a[i].y)-vy.begin()+1;
}
sort(a+1, a+1+n);
tree[1].s = 1, tree[1].e = MAXN;
for (int i = 2; i <= MAXN*4; i++) {
int s = tree[i/2].s, e = tree[i/2].e;
if (i%2) s = (s+e)/2+1;
else e = (s+e)/2;
tree[i] = { s,e,-INF,-INF,-INF };
}
ll dap = -INF;
int chk[3333] = {};
for (int i = 1; i <= n; i++) {
if (a[i-1].x != a[i].x) chk[i] = 1;
}
for (int i = 1; i <= n; i++) {
if (!chk[i]) continue;
ll cur = -INF;
for (int j = i; j <= n; j++) {
update(j);
if (chk[j+1] || j == n) cur = max(cur, tree[1].mmax);
}
dap = max(dap, cur);
for (int i = 1; i <= MAXN*2; i++) {
tree[i].mmax = tree[i].lmax = tree[i].rmax = -INF;
if (i <= MAXN) t[i] = 0;
}
}
printf("%lld\n", dap);
return 0;
}
아무말
백준, 백준 온라인 저지, BOJ, Baekjoon Online Judge, C, C++, 씨, 씨쁠쁠, JAVA, algorithm, 자바, 알고리즘, 자료구조, 문제, 문제 풀이, 풀이