AtCoder Beginner Contest 464 E-Fill-Rect Query 题解

当时写的时候犯了糖......

错误解法

我第一眼看这题的时候想到了线段树
我们可以写一个哈希函数将一个二维数组映射为一维
将每一次修改分段处理(类似于树链剖分)
输出时单点查询即可
这样修改的复杂度最大为 \(O(hlog(hw))\)
查询总复杂度为 \(O(hwlog(hw))\)
按理说没有任何问题
but它T掉了
估计是有特殊构造(比如 \(h=10^6,w=1\)

错误code

#include<bits/stdc++.h>
using namespace std;
#define lid (id<<1)
#define rid (id<<1|1)
const int NUM=1e6+10;

struct tree{
	int l,r;
	int col='A';
	int lazy='A';
}T[NUM<<2];
void pushdown(int id){
	if(T[id].lazy!='A'){
		int lz=T[id].lazy;
		T[id].lazy='A';
		T[lid].col=lz;
		T[rid].col=lz;
		T[lid].lazy=lz;
		T[rid].lazy=lz;
	}
}
void build(int id,int l,int r){
	T[id].l=l,T[id].r=r;
	if(l==r){
		T[id].col='A';
		return;
	}
	int mid=(l+r)>>1;
	build(lid,l,mid);
	build(rid,mid+1,r);
}
void update(int id,int l,int r,int val){
	if(l<=T[id].l&&T[id].r<=r){
		T[id].lazy=val;
		T[id].col=val;
		return;
	}
	pushdown(id);
	int mid=(T[id].l+T[id].r)>>1;
	if(l<=mid) update(lid,l,r,val);
	if(r>mid) update(rid,l,r,val);
}
char query(int id,int pos){
	if(T[id].l==T[id].r){
		return T[id].col;
	}
	pushdown(id);
	int mid=(T[id].l+T[id].r)>>1;
	if(pos<=mid) return query(lid,pos);
	if(pos>mid) return query(rid,pos);
}

int h,w,q;
int mp1(int i,int j){
	return (i-1)*w+j; 
}
void update1(int H,int W,int X){
	for(int i=1;i<=H;++i) update(1,mp1(i,1),mp1(i,W),X);
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>h>>w>>q;
	build(1,mp1(1,1),mp1(h,w)+10);
	for(int i=1,R,C;i<=q;++i){
		char X;
		cin>>R>>C>>X;
		update1(R,C,X);
	}
	for(int i=1;i<=h;++i){
		for(int j=1;j<=w;++j){
			cout<<query(1,mp1(i,j));
		}cout<<'\n';
	}
	return 0;
}

正确解法

其实这非常简单
\(G\) 就是这个 \(H \times W\) 的矩阵,且初始值为一
对于每一次修改,将 \(G_{R_i,C_i}\) 修改为 \(i\),并记录每一个 \(X_i\)
记第 \(i\) 行,第 \(j\) 列的答案为 \(ans_{i,j}\)
然后就会发现 \(ans_{i,j}=\max_{i\le x\le H,j\le y\le W}{G_{x,y}}\)
说白了就是后缀最大值
我们倒着跑一遍 \(ans_{i,j}=\max{\{G_{i,j},ns_{i+1,j},ans_{i,j+1},ans_{i+1,j+1}\}}\)
然后对于每一个 \(ans_{i,j},\forall i \in [1,H],\forall j \in [1,W]\) 输出对应的 \(X\) 即可

AC code

#include<bits/stdc++.h>
using namespace std;
const int NUM=1e6+10;

int h,w,q;
char X[NUM]={'A'};

int mymax(int a,int b,int c,int d){
	return max(max(a,b),max(c,d)); 
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	
	cin>>h>>w>>q;
	vector<vector<int> > mp(h+2,vector<int>(w+2,0));
	
	for(int i=1,R,C;i<=q;++i){
		cin>>R>>C>>X[i];
		mp[R][C]=i;
	}
	for(int i=h;i>=1;--i){
		for(int j=w;j>=1;--j){
			mp[i][j]=mymax(mp[i][j],mp[i+1][j],mp[i][j+1],mp[i+1][j+1]);
		}
	}
	for(int i=1;i<=h;++i){
		for(int j=1;j<=w;++j){
			cout<<X[mp[i][j]];
		}cout<<'\n';
	}
	return 0;
}

解释一下

vector<vector<int> > mp(h+2,vector<int>(w+2,0));

这是指建立一个长为 \(h+2\),宽为 \(w+2\),初始值为 \(0\),的二维数组
为神魔是 \(+2\)
因为 vector 下标从零开始,且求 \(max\) 时需要访问到 \(mp_{h+1,w+1}\)
吐槽一句,为什么atcoder官解使用PYPY写的。

posted @ 2026-06-28 08:01  LZYXT  阅读(22)  评论(1)    收藏  举报