[Comet OJ

C 给定1000*1000的矩阵,每次将一个子矩阵内全部值赋值为1,问四联通块数量 Q 3e4

首先考虑复杂度,3e4次操作的合并暴力肯定不行,并且要考虑已经为1的块不应该再次考虑

1.考虑合并操作,对于一个0点,当他变为1对答案的影响只有几种情况

周边都是0,总联通联通块数量加1

周边有(1 - 4)个不同联通块,ans -= 不同联通块个数+1

对于相同的联通块通过当前0点合并没有意义,不用计算。

所以对于每个0点的合并可以快速计算并用并查集合并(映射下标)

2.然后考虑第二个问题,如何让每个0点只被操作一次

可以用并查集维护每行当前点的下一个0点,这样在区间上跳动速度飞快并且每次跳的都是0点

或者用set维护当前行内还有0的下标并操作erase(比并查集常数大)

/*
    Zeolim - An AC a day keeps the bug away
*/
 
//#pragma GCC optimize(2)
//#pragma GCC ("-W1,--stack=128000000")
#include <bits/stdc++.h>
using namespace std;
#define mp(x, y) make_pair(x, y)
#define fr(x, y, z) for(int x = y; x < z; ++x)
#define pb(x) push_back(x)
#define mem(x, y) memset(x, y, sizeof(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef std::pair <int, int> pii;
typedef std::vector <int> vi;
//typedef __int128 ill;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 386910137;
const ull P = 13331; 
const int MAXN = 3e6 + 100;

int n, m;
int fa[MAXN] = {0};
int mov[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
bool arr[1010][1010] = {0};

struct uni
{
	int fa[1010] = {0};
	uni() { for(int i = 0; i < 1010; ++i) fa[i] = i; }
	int findfa(int x) { return x == fa[x] ? x : fa[x] = findfa(fa[x] ); }
}u[1010];

int findfa(int x) { return fa[x] == x ? x : fa[x] = findfa(fa[x]); }

int ans = 0;
int getp(int x, int y) { return x * m + y; }
struct node { int x, y, fa; };

void uni(int x, int y)
{
	++ans;  
	int tox, toy, p, q;
	p = findfa(getp(x, y));
	
	for(int i = 0; i < 4; ++i) //统计不同联通块的数量并计算贡献 
	{
		tox = x + mov[i][0], toy = y + mov[i][1];
		if(arr[tox][toy])
		{
			q = findfa(getp(tox, toy)); 
			if(p != q) { fa[q] = p; --ans; } //不同联通块才有贡献 
		}		
	}
}

void init()
{
	for(int i = 0; i < 1010; ++i)
		for(int j = 0; j < 1010; ++j)
			fa[getp(i, j)] = getp(i, j);
			
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= m; ++j) //维护第i行第j列后面的第一个0 
		{
			if(!arr[i][j]) u[i].fa[j] = j;
			else u[i].fa[j] = j + 1;
		}
	}
	 
	for(int i = 1; i <= n; ++i) //初始化合并矩阵信息 
	{
		for(int j = 1; j <= m; ++j)
		{
			if(!arr[i][j]) continue;
			uni(i, j);
		}
	}
}

void put()
{
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= m; ++j)
		{
			cout << arr[i][j];
		}
		cout << '
';
	}
}

int main()
{  
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    //freopen("d:out.txt","w",stdout);
    //freopen("d:in.txt","r",stdin);
    
	cin >> n >> m; 
	
	char x;
		
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= m; ++j)
		{
			cin >> x;
			arr[i][j] = (x == '1');
		}
	}
	
	init();
	
	//cout << ans << '
';
	
	int q;
	
	cin >> q;
	
	while(q--)
	{
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		
		for(int i = x1; i <= x2; ++i) //操作区间内1 
		{
			for(int j = u[i].findfa(y1); j <= y2; j = u[i].findfa(j))
			{
				arr[i][j] = 1;
				u[i].fa[j] = j + 1;
				uni(i, j);
			}
		}
		
		//put();
		cout << ans << '
';
	}
	
    
    return 0;
}

B 贪吃蛇,wsad上下左右移动,吃住x头变长,不吃整体移动,问最终形态

用双端队列可以很容易的维护当前状态见代码

/*
    Zeolim - An AC a day keeps the bug away
*/
 
//#pragma GCC optimize(2)
//#pragma GCC ("-W1,--stack=128000000")
#include <bits/stdc++.h>
using namespace std;
#define mp(x, y) make_pair(x, y)
#define fr(x, y, z) for(int x = y; x < z; ++x)
#define pb(x) push_back(x)
#define mem(x, y) memset(x, y, sizeof(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef std::pair <int, int> pii;
typedef std::vector <int> vi;
//typedef __int128 ill;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 386910137;
const ull P = 13331; 
const int MAXN = 3e6 + 100;
int mov[4][2] = {{0, 1},{1, 0},{-1,0},{0,-1}};
struct pit { int x, y; };
char arr[410][410] = {0};
int n, m;
bool inmap(int x, int y) { return (x >= 1 && x <= n && y >= 1 && y <= m); }
int main()
{  
    
    cin >> n >> m;
    deque <pit> Q;
    for(int i = 1; i <= n; ++i)
    {
    	for(int j = 1; j <= m; ++j)
    	{
    		cin >> arr[i][j];
    		if(arr[i][j] == '@')
    		{
    			Q.push_back(pit{i, j});
    			arr[i][j] = '.';
			}
		}
	}
	map <char, int> MP;
	MP['W'] = 2, MP['A'] = 3, MP['S'] = 1, MP['D'] = 0;
	string opt;
	cin >> opt;
	int p, tox, toy, rtox, rtoy;
	for(auto x : opt)
	{
		p = MP[x], tox = Q.front().x, toy = Q.front().y;
		tox += mov[p][0], toy += mov[p][1];
		if(!inmap(tox, toy)) { cout << "GG
"; return 0; }
		if(arr[tox][toy] == 'o') 
		{
			arr[tox][toy] = '.';
			Q.push_front(pit{tox, toy});
		}
		else
		{
			rtox = Q.back().x, rtoy = Q.back().y;
			Q.pop_back();
			Q.push_front(pit{tox, toy});
			rtox = Q[1].x, rtoy = Q[1].y;
		}
	}
	
	while(Q.size() > 1)
	{
		arr[Q.back().x][Q.back().y] = 'X';
		Q.pop_back();
	}
	arr[Q.back().x][Q.back().y] = '@';
	
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= m; ++j)
		{
			cout << arr[i][j];
		}
		cout << '
';
	}
    return 0;
}
原文地址:https://www.cnblogs.com/zeolim/p/12270320.html