1. 程式人生 > 實用技巧 >XJOI contest 1570 Problem B

XJOI contest 1570 Problem B

這道題是我考場上唯一有把握的一道題,結果文體兩開花,時空雙爆炸……

題意

給你一個 \(n\times m\)\(01\) 矩陣,同時還有 \(k\) 個操作,每一次操作會使得一個位置的 \(0\) 變成 \(1\) ,詢問每一個操作後矩陣的最大的全為 \(0\) 的正方形子矩陣邊長。

題解

我們可以定義一種狀態 \(f_{i,j}\) 表示以點 \((i,j)\) 作為正方形右下角時,最長的正方形邊長。對於一開始的矩陣,我們不難用 \(O(n^2)\) 的時間來求出這個東西,然後我們考慮修改。

我們發現,如果我們在 \((i,j)\) 這個位置改 \(0\)\(1\) ,我們會使得之後的節點的 \(f{i,j}\)

的上限減少,本質上就是一個區間取 \(min\) 。我們用二維線段樹就可以了。

\(0pts\) 程式碼如下:

#include<bits/stdc++.h>
using namespace std;
const int N=2005,K=2005;
int n,m,k;
bool mp[N][N];
int d[N][N];
struct Seg_Tree
{
	int now=1;
	struct Node{int ls,rs,data,tag;}tr[4105];
	void up(int u){tr[u].data=max(tr[tr[u].ls].data,tr[tr[u].rs].data);}
	void updata(int u,int z)
	{
		tr[u].data=min(tr[u].data,z);
		tr[u].tag=min(tr[u].tag,z);
	}
	void down(int u)
	{
		updata(tr[u].ls,tr[u].tag);
		updata(tr[u].rs,tr[u].tag);
		tr[u].tag=1e9+7;
	}
	void build(int u,int l,int r,int a[])
	{
		tr[u].tag=1e9+7;
		if(l==r){tr[u].data=a[l];return;}
		int mid=(l+r)>>1;
		tr[u].ls=++now;
		build(tr[u].ls,l,mid,a);
		tr[u].rs=++now;
		build(tr[u].rs,mid+1,r,a);
		up(u);
	}
	void change(int u,int l,int r,int x,int y,int z)
	{
		if(x<=l&&r<=y){updata(u,z);return;}
		int mid=(l+r)>>1;
		down(u);
		if(x<=mid) change(tr[u].ls,l,mid,x,y,z);
		if(y>mid) change(tr[u].rs,mid+1,r,x,y,z);
		up(u);
	}
};
struct Chg{int x,y,z;};
struct Seg_Tree_2
{
	int now=1;
	struct Node{int ls,rs;Seg_Tree data;vector<Chg> tag;}tr[4105];
	void up(int u)
	{
		if(tr[tr[u].ls].data.tr[1].data>tr[tr[u].rs].data.tr[1].data)
		tr[u].data=tr[tr[u].ls].data;
		else tr[u].data=tr[tr[u].rs].data;
	}
	void updata(int u,Chg z)
	{
		tr[u].data.change(1,1,m,z.x,z.y,z.z);
		tr[u].tag.push_back(z);
	}
	void down(int u)
	{
		for(int i=0;i<tr[u].tag.size();++i)
		{
			updata(tr[u].ls,tr[u].tag[i]);
			updata(tr[u].rs,tr[u].tag[i]);
		}
		vector<Chg> ept;
		tr[u].tag.swap(ept);
	}
	void build(int u,int l,int r)
	{
		if(l==r){tr[u].data.build(1,1,m,d[l]);return;}
		int mid=(l+r)>>1;
		tr[u].ls=++now;
		build(tr[u].ls,l,mid);
		tr[u].rs=++now;
		build(tr[u].rs,mid+1,r);
		up(u);
	}
	void change(int u,int l,int r,int x,int y,Chg z)
	{
		if(x<=l&&r<=y){updata(u,z);return;}
		int mid=(l+r)>>1;
		down(u);
		if(x<=mid) change(tr[u].ls,l,mid,x,y,z);
		if(y>mid) change(tr[u].rs,mid+1,r,x,y,z);
		up(u);
	}
}t;
int main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=m;++j)
		{
			char c;cin>>c;
			mp[i][j]=(c=='X');
		}
	}
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=m;++j)
		{
			if(mp[i][j]) continue;
			d[i][j]=min(d[i-1][j]+1,d[i][j-1]+1);
			if(d[i-1][j]==d[i][j-1]&&mp[i-d[i][j]+1][j-d[i][j]+1]) d[i][j]--;
		}
	}
	// for(int i=1;i<=n;++i)
	// {
	// 	for(int j=1;j<=m;++j)
	// 	printf("%d ",d[i][j]);
	// 	printf("\n");
	// }
	t.build(1,1,n);
	for(int i=1,x,y;i<=k;++i)
	{
		scanf("%d%d",&x,&y);
		for(int j=0;j<=max(n-x,m-y);++j)
		t.change(1,1,n,x,x+j,Chg{y,y+j,j});
		printf("%d\n",t.tr[1].data.tr[1].data);
	}
}