题解 跑步

传送门

首先一个 \(O(n^2)\) 的 DP 是显然的
然后赛时脑子抽了试图单次 \(O(\log n)\)\(O(\log^2 n)\) 维护答案变化
事实上可以支持单次 \(O(n\log n)\)

因为单点权值变化量只有 1
所以如果一个点的 DP 值变了那一定和这次修改的变化量相同
发现一个位置的值变不变之和左上有关
所以一次修改在每一行影响的范围 \([l_i, r_i]\) 满足 \(l_i, r_i\) 均单调不降
那就可以单调指针+树状数组
(如果单点权值变化量不止 1 就不能这样做了,仍然可以确定有哪些位置的值变了但不知道变了多少)
复杂度 \(O(n^2\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2010
#define fir first
#define sec second
#define ll long long
//#define int long long

int n;
int a[N][N];
ll f[N][N];
char op[10];

namespace force{
	void recalc() {
		ll ans=0;
		for (int i=1; i<=n; ++i)
			for (int j=1; j<=n; ++j)
				ans+=(f[i][j]=max(f[i-1][j], f[i][j-1])+a[i][j]);
		printf("%lld\n", ans);
	}
	void solve() {
		recalc();
		for (int i=1,x,y; i<=n; ++i) {
			scanf("%s%d%d", op, &x, &y);
			if (*op=='U') ++a[x][y];
			else --a[x][y];
			recalc();
		}
	}
}

namespace task1{
	ll ans;
	bool vis[N][N];
	queue<pair<int, int>> q;
	void recalc() {
		ans=0;
		for (int i=1; i<=n; ++i)
			for (int j=1; j<=n; ++j)
				ans+=(f[i][j]=max(f[i-1][j], f[i][j-1])+a[i][j]);
	}
	void bfs(pair<int, int> s) {
		q.push(s);
		while (q.size()) {
			pair<int, int> u=q.front(); q.pop();
			int i=u.fir, j=u.sec, t=max(f[i-1][j], f[i][j-1])+a[i][j], x, y;
			vis[i][j]=0;
			if (t==f[i][j]) continue;
			ans=ans-f[i][j]+t; f[i][j]=t;
			x=i+1, y=j; if (x<=n && y<=n && !vis[x][y]) q.push({x, y}), vis[x][y]=1;
			x=i, y=j+1; if (x<=n && y<=n && !vis[x][y]) q.push({x, y}), vis[x][y]=1;
		}
	}
	void solve() {
		recalc();
		printf("%lld\n", ans);
		for (int i=1,x,y; i<=n; ++i) {
			scanf("%s%d%d", op, &x, &y);
			if (*op=='U') ++a[x][y];
			else --a[x][y];
			bfs({x, y});
			printf("%lld\n", ans);
		}
	}
}

namespace task{
	ll ans=0;
	struct bit{
		ll a[N];
		inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) a[i]+=dat;}
		inline ll query(int i) {ll ans=0; for (; i; i-=i&-i) ans+=a[i]; return ans;}
		inline void upd(int l, int r, int dat) {upd(l, dat); upd(r+1, -dat);}
		inline ll operator [] (int t) {return query(t);}
	}bit[N];
	void recalc() {
		ans=0;
		for (int i=1; i<=n; ++i)
			for (int j=1; j<=n; ++j)
				ans+=(f[i][j]=max(f[i-1][j], f[i][j-1])+a[i][j]), bit[i].upd(j, j, f[i][j]);
	}
	void modify(pair<int, int> s, int k) {
		int l=s.sec, r=s.sec;
		for (int i=s.fir; i<=n; ++i) {
			while (l<=n && bit[i][l]==max(bit[i-1][l], bit[i][l-1])+a[i][l]) ++l;
			r=max(l, r);
			while (r<=n && bit[i][r]!=max(bit[i-1][r], bit[i][r-1]+k)+a[i][r]) ++r;
			if (l<=r-1) bit[i].upd(l, r-1, k), ans+=(r-l)*k;
		}
	}
	void solve() {
		recalc();
		printf("%lld\n", ans);
		for (int i=1,x,y; i<=n; ++i) {
			scanf("%s%d%d", op, &x, &y);
			if (*op=='U') ++a[x][y];
			else --a[x][y];
			modify({x, y}, *op=='U'?1:-1);
			printf("%lld\n", ans);
		}
	}
}

signed main()
{
	freopen("run.in", "r", stdin);
	freopen("run.out", "w", stdout);

	scanf("%d", &n);
	for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) scanf("%d", &a[i][j]);
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2022-03-14 21:25  Administrator-09  阅读(1)  评论(0编辑  收藏  举报