前言
可惜今天调试环境花太久时间,之后还在走廊无意义随机游走,所以三四题没时间了QAQ
不然三四题至少出一道。
题目
讲解
考虑直接求出每个块的下落距离。
如果单独一个点一个点看,那么会造成影响的只会是一列当中的两个元素,设他们的坐标为 ((x_1,y),(x_2,y),x_1>x_2)。
设下落距离为 (dis),那么显然有 (dis_2+x_1-x_2-1ge dis_1),是一个差分约束的形式,然后我们把每个单点带回连通块,求出连通块两两之间的限制,直接跑差分约束即可。
时间复杂度 (O(nmlog_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('
'))
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('
'))
for(int j = 1;j <= m;++ j)
putchar(G[i][j]);
return 0;
}