题目
分析
把所有边按照u排序,设f[i][j]为左边前i个点右边前j个点都不能被连接了,那么
f[i][j] = max{ f[q][p] + vx[i] + vy[j] | q < i and p < j and (i, j) ∈ E }
明显上面一种DP方法是可以改的。
f[i][j] = max{ f[i-1][k] + vx[i] + vy[j] | k < j and (i, j) ∈ E, f[i-1][j], f[i][j-1], f[i-1][j-1]}
观察上面求最大值的部分,是一段连续的值,那么明显可以使用线段树或者树状数组快速求得。
把边的第二维作为第二关键字从大到小排序,那么就可以利用一个树状数组或者线段树,可以节省一点空间。
代码
#include <bits/stdc++.h>
const int N = 5e5 + 5;
int read()
{
int x = 0, f = -1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar();}
return x;
}
struct Note
{
int x,y;
}q[N];
int v[N],s[N];
int n,m;
bool cmp(Note a,Note b)
{
return a.x == b.x ? a.y > b.y : a.x < b.x;
}
int t[N];
int f[N];
int query(int x)
{
int ans = 0;
while (x)
{
ans = std::max(ans, t[x]);
x -= x & (-x);
}
return ans;
}
void add(int x,int val)
{
while (x <= m)
{
t[x] = std::max(val, t[x]);
x += x & (-x);
}
}
int main()
{
n = read(), m = read();
for (int i = 1; i <= m; i++)
q[i].x = read(), q[i].y = read();
for (int i = 1; i <= n; i++)
s[i] = read();
for (int i = 1; i <= n; i++)
v[i] = read();
std::sort(q + 1, q + m + 1, cmp);
for (int i = 1; i <= m; i++)
{
f[q[i].y] = std::max(f[q[i].y], query(std::max(q[i].y - 1,0)) + s[q[i].y] + v[q[i].x]);
add(q[i].y,f[q[i].y]);
}
printf("%d\n",query(m));
}