[洛谷P5532] [CCO 2019] Sirtet

前言

可惜今天调试环境花太久时间,之后还在走廊无意义随机游走,所以三四题没时间了QAQ

不然三四题至少出一道。

题目

洛谷

讲解

考虑直接求出每个块的下落距离。

如果单独一个点一个点看,那么会造成影响的只会是一列当中的两个元素,设他们的坐标为 \((x_1,y),(x_2,y),x_1>x_2\)

设下落距离为 \(dis\),那么显然有 \(dis_2+x_1-x_2-1\ge dis_1\),是一个差分约束的形式,然后我们把每个单点带回连通块,求出连通块两两之间的限制,直接跑差分约束即可。

时间复杂度 \(O(nm\log_2nm)\)

据说还有模拟做法?

代码

赛后改动不大的代码
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;

typedef long long LL;
const int MAXN = 1000005;
const int INF = 0x3f3f3f3f;
int n,m;
vector<char> G[MAXN];
vector<int> a[MAXN],d[2][MAXN];
int dx[4] = {1,-1},dy[4] = {0,0,1,-1};

LL Read()
{
	LL x = 0,f = 1; char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

char gc()
{
	char c = getchar();
	while(c != '.' && c != '#') c = getchar();
	return c;
}
int f[MAXN];
int findSet(int x){if(f[x]^x)f[x]=findSet(f[x]);return f[x];}
void unionSet(int x,int y)
{
	x = findSet(x); y = findSet(y);
	if(x^y) f[x] = y;
}
int bl[MAXN];
int ID(int x,int y){return (x-1)*m+y;}
int IDtot;
struct node{int x,y;bool operator < (const node &px)const{return y > px.y;};};
vector<node> g[MAXN];

void solve1()
{
	int cnt = 0;
	for(int i = 1;i <= n;++ i)
		if(G[i][1] == '#') ++cnt;
	for(int i = 1;i <= n;++ i,putchar('\n'))
		if(i+cnt <= n) putchar('.');
		else putchar('#');
}

int head[MAXN],tot;
struct edge
{
	int v,w,nxt;
}e[MAXN << 1];
void Add_Edge(int x,int y,int z)
{
	e[++tot] = edge{y,z,head[x]};
	head[x] = tot;
}
void Add_Double_Edge(int x,int y,int z)
{
	Add_Edge(x,y,z);
	Add_Edge(y,x,z);
}

int dis[MAXN];
void dij()
{
	for(int i = 1;i <= IDtot;++ i) dis[i] = INF;
	priority_queue<node> q;
	q.push(node{0,0});
	while(!q.empty())
	{
		node t = q.top(); q.pop();
		if(t.y > dis[t.x]) continue;
		for(int i = head[t.x]; i ;i = e[i].nxt)
			if(t.y+e[i].w < dis[e[i].v])
				q.push(node{e[i].v,dis[e[i].v] = t.y+e[i].w}); 
	}
}

int main()
{
//	freopen("tpt.in","r",stdin);
//	freopen("tpt.out","w",stdout);
	n = Read(); m = Read();
	for(int i = n*m;i >= 1;-- i) f[i] = i;
	for(int i = 1;i <= n;++ i)
	{
		G[i].resize(m+2);
		d[0][i].resize(m+2);
		d[1][i].resize(m+2);
		for(int j = 1;j <= m;++ j) G[i][j] = gc();
	}
	if(m == 1){solve1();return 0;}
	d[0][n+1].resize(m+2);
	d[1][n+1].resize(m+2);
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j <= m;++ j)
		{
			if(G[i][j] == '.') continue;
			for(int k = 0;k < 4;++ k)
			{
				int tox = i+dx[k],toy = j+dy[k];
				if(tox >= 1 && toy >= 1 && tox <= n && toy <= m && G[tox][toy] == '#')
					unionSet(ID(i,j),ID(tox,toy));
			}
		}
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j <= m;++ j)
		{
			if(G[i][j] == '.') continue;
			int rt = findSet(ID(i,j));
			if(!bl[rt]) bl[rt] = ++IDtot;
			bl[ID(i,j)] = bl[rt];
			g[bl[rt]].emplace_back(node{i,j});
		}
	for(int i = 1;i <= m;++ i) d[0][n+1][i] = n+1,d[1][n+1][i] = i;
	for(int i = n;i >= 1;-- i)
		for(int j = 1;j <= m;++ j)
			if(i == n || G[i+1][j] == '#') d[0][i][j] = i+1,d[1][i][j] = j;
			else d[0][i][j] = d[0][i+1][j],d[1][i][j] = d[1][i+1][j];
	 for(int i = 1;i <= n;++ i)
	 	for(int j = 1;j <= m;++ j)
	 		if(G[i][j] == '#')
	 		{
	 			if(d[0][i][j] > n) Add_Edge(0,bl[ID(i,j)],d[0][i][j]-i-1);
	 			else if(bl[ID(d[0][i][j],d[1][i][j])]^bl[ID(i,j)]) Add_Edge(bl[ID(d[0][i][j],d[1][i][j])],bl[ID(i,j)],d[0][i][j]-i-1);
			}
	dij();
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j <= m;++ j)
			G[i][j] = '.';
	for(int i = 1;i <= IDtot;++ i)
		for(auto A : g[i])
			G[A.x+dis[i]][A.y] = '#';
	for(int i = 1;i <= n;++ i,putchar('\n'))
		for(int j = 1;j <= m;++ j)
			putchar(G[i][j]);
	return 0;
}
posted @ 2021-10-15 15:45  皮皮刘  阅读(77)  评论(0)    收藏  举报