Codeforces Round #318 D. Bear and Cavalry 线段树维护矩阵乘法维护DP

版权声明:xgc原创文章,未经允许不得转载。 https://blog.csdn.net/xgc_woker/article/details/82911026

Description
有n个人和n匹马,第i个人对应第i匹马。第i个人能力值wi,第i匹马能力值hi,第i个人骑第j匹马的总能力值为wi*hj,整个军队的总能力值为∑wihj(一个人只能骑一匹马,一匹马只能被一个人骑)。有一个要求:每个人都不能骑自己对应的马。让你制定骑马方案,使得整个军队的总能力值最大。现在有q个操作,每次给出a,b,交换a和b对应的马。每次操作后你都需要输出最大的总能力值。


Sample Input
4 2
1 10 100 1000
3 7 2 5
2 4
2 4


Sample Output
5732
7532


有一个比较显然的结论是肯定是会和相邻的两个匹配。
然后你就可以用DP,DP的话只跟前两项有关系可以建立3*3的矩阵优化。
然后这个玩意可以用线段树优化???
点了一波技能树好吧。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
LL _min(LL x, LL y) {return x < y ? x : y;}
LL _max(LL x, LL y) {return x > y ? x : y;}
LL read() {
	LL s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

struct node {
	LL x; int id;
} a[31000], b[31000];
int fac[31000], pos[31000];
bool ck(int x, int y) {return fac[a[x].id] != b[y].id;}
struct matrix {
	LL m[3][3]; int l, r, lc, rc;
	friend matrix operator * (matrix a, matrix b) {
		matrix c;
		memset(c.m, -31, sizeof(c.m));
		for(int i = 0; i < 3; i++) {
			for(int j = 0; j < 3; j++) {
				for(int k = 0; k < 3; k++) {
					c.m[i][j] = _max(c.m[i][j], a.m[i][k] + b.m[k][j]);
				}
			}
		} return c;
	}
	void update(int x) {
		memset(m, -31, sizeof(m));
		if(ck(x, x)) m[0][0] = a[x].x * b[x].x;
		if(x > 1 && ck(x, x - 1) && ck(x - 1, x)) m[1][0] = a[x].x * b[x - 1].x + a[x - 1].x * b[x].x;
		if(x > 2 && ck(x, x - 2) && ck(x - 1, x) && ck(x - 2, x - 1)) m[2][0] = _max(m[2][0], a[x].x * b[x - 2].x + a[x - 1].x * b[x].x + a[x - 2].x * b[x - 1].x);
		if(x > 2 && ck(x, x - 1) && ck(x - 2, x) && ck(x - 1, x - 2)) m[2][0] = _max(m[2][0], a[x].x * b[x - 1].x + a[x - 2].x * b[x].x + a[x - 1].x * b[x - 2].x);
		if(x > 2 && ck(x, x - 2) && ck(x - 1, x - 1) && ck(x - 2, x)) m[2][0] = _max(m[2][0], a[x].x * b[x - 2].x + a[x - 1].x * b[x - 1].x + a[x - 2].x * b[x].x);
		m[0][1] = m[1][2] = 0;
	}
} t[61000]; int cnt;

bool cmp(node a, node b) {
	if(a.x == b.x) return a.id < b.id;
	return a.x < b.x;
}

void bt(int l, int r) {
	int now = ++cnt;
	t[now].l = l, t[now].r = r;
	t[now].lc = t[now].rc = -1;
	if(l < r) {
		int mid = (l + r) / 2;
		t[now].lc = cnt + 1; bt(l, mid);
		t[now].rc = cnt + 1; bt(mid + 1, r);
	}
}

void change(int now, int p) {
	if(t[now].l == t[now].r) {t[now].update(t[now].l); return ;}
	int mid = (t[now].l + t[now].r) / 2;
	if(p <= mid) change(t[now].lc, p);
	else change(t[now].rc, p);
	int l = t[now].l, r = t[now].r, lc = t[now].lc, rc = t[now].rc;
	t[now] = t[t[now].lc] * t[t[now].rc];
	t[now].l = l, t[now].r = r, t[now].lc = lc, t[now].rc = rc;
}

int main() {
	int n = read(), m = read();
	for(int i = 1; i <= n; i++) a[i].x = read(), a[i].id = i;
	for(int i = 1; i <= n; i++) b[i].x = read(), b[i].id = i;
	sort(a + 1, a + n + 1, cmp), sort(b + 1, b + n + 1, cmp);
	for(int i = 1; i <= n; i++) fac[i] = i;
	bt(1, n);
	for(int i = 1; i <= n; i++) pos[a[i].id] = i, change(1, i);
	for(int i = 1; i <= m; i++) {
		int x = read(), y = read();
		swap(fac[x], fac[y]);
		for(int i = pos[x]; i <= _min(n, pos[x] + 2); i++) change(1, i);
		for(int i = pos[y]; i <= _min(n, pos[y] + 2); i++) change(1, i);
		printf("%lld\n", t[1].m[0][0]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/82911026