杭电多校4 1012
题意:
给定
n
n
n个点和
m
m
m个矩形,每个点有一个权值,从
(
0
,
0
)
(0,0)
(0,0)出发,只能向上和向右走,要求对于每个矩阵求出在不经过该矩阵的情况下,你能经过的最大的点权和。
题解:
考虑划分矩形区域,将答案分为四种情况讨论,如图,
S
1
S1
S1为挑选的矩形区域
1.经过
S
3
,
S
5
,
S
7
S3,S5,S7
S3,S5,S7三个矩形达到右上角(必然经过
S
5
S5
S5中的至少一个点)
2.经过
S
2
,
S
4
,
S
6
S2,S4,S6
S2,S4,S6三个矩形达到右上角(必然经过
S
4
S4
S4中的至少一个点)
3.经过
S
3
,
S
7
S3,S7
S3,S7两个矩形达到右上角(不经过任何
S
5
S5
S5中的点)
4.经过
S
2
,
S
6
S2,S6
S2,S6两个矩形达到右上角(不经过任何
S
4
S4
S4中的点)
分类之后我们就可以考虑如何计算矩形内的贡献了
显然,我们需要计算三个值:
f
(
x
)
:
f(x):
f(x):从
0
0
0到
x
x
x这个位置上的点的最大点权和,
g
(
x
)
:
g(x):
g(x):从
x
x
x这个位置上的点到
n
n
n的最大点权和,
h
(
x
)
:
h(x):
h(x):经过
x
x
x这个位置上的点的最大点权和。其中
h
(
x
)
=
f
(
x
)
+
g
(
x
)
−
v
x
h(x) = f(x) + g(x) - v_x
h(x)=f(x)+g(x)−vx。
这三个值通过线段树优化DP即可维护,而四种情况通过扫描线从左往右扫,扫四遍,第一遍扫
S
2
,
S
3
S2,S3
S2,S3,第二遍扫
S
6
,
S
7
S6,S7
S6,S7,并维护出
h
(
x
)
h(x)
h(x),第三遍和第四遍通过维护出的
h
(
x
)
h(x)
h(x)扫
S
4
,
S
5
S4,S5
S4,S5,最后取最值即可。
真别写线段树,会被卡常
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
// #define int long long
#define debug(p) for (auto i : p)cerr << i << " "; cerr << endl;
#define debugs(p) for (auto i : p)cerr << i.first << " " << i.second << endl;
typedef pair<int, int> pll;
string yes = "YES";
string no = "NO";
constexpr int N = 3e5 + 7;
struct Seg_tree{
long long maxx;
}tr[N * 4];
struct Info{
int xl, xr, yl, yr;
long long lu, rd;
long long ans;
}info[N];
int p[N];
long long f[N], g[N], h[N], w[N];
vector<int>xl[N], xr[N];
inline void push_up(int u)
{
tr[u].maxx = max(tr[u << 1].maxx, tr[u << 1 | 1].maxx);
}
void build(int u, int l, int r)
{
if(l == r)
{
tr[u].maxx = w[l];
return;
}
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
push_up(u);
}
void modify(int u, int l, int r, int pos, long long x)
{
if(l == r)
{
tr[u].maxx = x;
return;
}
int mid = l + r >> 1;
if(pos <= mid)modify(u << 1, l, mid, pos, x);
else modify(u << 1 | 1, mid + 1, r, pos, x);
push_up(u);
}
long long query(int u, int l, int r, int ql, int qr)
{
if(ql > qr)return 0ll;
if(ql <= l && r <= qr)return tr[u].maxx;
int mid = l + r >> 1;
long long res = 0ll;
if(ql <= mid)res = max(res, query(u << 1, l, mid, ql, qr));
if(qr > mid)res = max(res, query(u << 1 | 1, mid + 1, r, ql, qr));
return res;
}
void init(int u, int l, int r)
{
if(l == r)
{
tr[u].maxx = 0ll;
return;
}
int mid = l + r >> 1;
tr[u].maxx = 0ll;
init(u << 1, l, mid), init(u << 1 | 1, mid + 1, r);
// push_up(u);
}
void solve()
{
long long n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> p[i] >> w[i];
xl[i].clear();
xr[i].clear();
}
for (int i = 1; i <= m; i++)
{
cin >> info[i].xl >> info[i].yl >> info[i].xr >> info[i].yr;
xl[info[i].xl].push_back(i);
xr[info[i].xr].push_back(i);
}
init(1, 1, n);
for (int i = 1; i <= n; i++)
{
for (auto idx : xl[i])
{
info[idx].lu = query(1, 1, n, 1, info[idx].yr);
}
f[i] = query(1, 1, n, 1, p[i]) + w[i];
modify(1, 1, n, p[i], f[i]);
for (auto idx : xr[i])
{
info[idx].rd = query(1, 1, n, 1, info[idx].yl - 1);
}
}
init(1, 1, n);
for (int i = n; i >= 1; i--)
{
for (auto idx : xr[i])
{
info[idx].rd = info[idx].rd + query(1, 1, n, info[idx].yl, n);
}
g[i] = query(1, 1, n, p[i], n) + w[i];
h[i] = f[i] + g[i] - w[i];
modify(1, 1, n, p[i], g[i]);
for (auto idx : xl[i])
{
info[idx].lu = info[idx].lu + query(1, 1, n, info[idx].yr + 1, n);
}
}
init(1, 1, n);
for (int i = 1; i <= m; i++)info[i].ans = max(info[i].lu , info[i].rd);
for (int i = 1; i <= n; i++)
{
for (auto idx : xl[i])
{
info[idx].ans = max(info[idx].ans, query(1, 1, n, info[idx].yr, n));
}
modify(1, 1, n, p[i], h[i]);
}
init(1, 1, n);
for (int i = n; i >= 1; i--)
{
for (auto idx : xr[i])
{
info[idx].ans = max(info[idx].ans, query(1, 1, n, 1, info[idx].yl));
}
modify(1, 1, n, p[i], h[i]);
}
init(1, 1, n);
for (int i = 1; i <= m; i++)
{
cout << info[i].ans << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int T = 1;
cin >> T;
while(T--)
{
solve();
}
}