F - Sorting a Matrix
Time Limit: 3 sec / Memory Limit: 1024 MB
Score : 500 points
2
≤
H
×
W
≤
1
0
6
2≤H×W≤10^6
2≤H×W≤106
0
≤
A
i
,
j
≤
H
×
W
0≤A_{i,j} ≤H×W
0≤Ai,j≤H×W
题意
给定一个 h*w 的矩阵
且可以对任意为 0 的元素赋值(值可以不同)
可以进行以下两种操作任意次:
i)交换 2 行
ii)交换 2 列
询问操作后能否使矩阵满足
从上到下从左到右元素不递减
思路
首先我们易证矩阵中同一行的元素以及同一列的元素不会发生变化
先考虑矩阵中不包括0的情况:
我们记一行的最大值为Max 最小值为Min
那么对于一个满足条件的矩阵一定满足
M
a
x
i
<
=
M
i
n
i
+
1
Max_i<=Min_{i+1}
Maxi<=Mini+1
在满足这个条件后我们可以将每一列视为一个点
对每一行的元素 若
A
i
,
j
<
A
i
,
k
A_{i,j}<A_{i,k}
Ai,j<Ai,k 我们就连一条
i
−
>
k
i ->k
i−>k的有向边 然后只需要用拓扑排序判断最后的图是否为DAG即可
再考虑矩阵中不包括0的情况:
若我们的操作对所有的0元素进行跳过 那么我们可以将 0 元素赋为这个元素之前那个元素的值 可以发现 0 其实不会影响答案故我们在操作过程中忽略即可
但这样连接的复杂度为
O
(
H
∗
W
2
)
O(H*W^2)
O(H∗W2)
故我们考虑引入新的点
将一行中的点按元素值升序排列后
对于相同的值我们先到一个虚点上然后通过这个虚点去连接
并且只需要连接最小的大于其的点即可 因为边的传递不影响成环
Code
#include<bits/stdc++.h>
using namespace std;
#define __T int csT;scanf("%d",&csT);while(csT--)
const int mod=1e9+7;
const int maxn=2e5+3;
unordered_map<int,int> us;
int h,w,x;
struct node{
int l,r;
};
int cmp(node a,node b)
{
if(a.l!=b.l)return a.l<b.l;
return a.r<b.r;
}
int cmpv(node a,node b)
{
return a.l<b.l;
}
inline void sol()
{
scanf("%d%d",&h,&w);
vector<vector<int>> mt(h);
for(int i=0;i<h;++i)
{
for(int j=0;j<w;++j)
{
scanf("%d",&x);
mt[i].push_back(x);
}
}
vector<node> v;
for(int i=0;i<h;++i)
{
int mx=0,mn=1e9;
for(int j=0;j<w;++j)
{
if(mt[i][j]==0)continue;
mx=max(mx,mt[i][j]);
mn=min(mn,mt[i][j]);
}
if(mn==1e9)continue;
v.push_back({mn,mx});
}
sort(v.begin(),v.end(),cmp);
for(int i=1;i<v.size();++i)
{
if(v[i].l<v[i-1].r)
{
puts("No");
return;
}
}
us.clear();
int id=w+1;
vector<vector<int>> to(h*w+w+3);
vector<int> in(h*w+w+3);
vector<node> at;
for(int i=0;i<h;++i)
{
at.clear();
for(int j=0;j<w;++j)
{
if(mt[i][j]>0)at.push_back({mt[i][j],j});
}
sort(at.begin(),at.end(), cmpv);
int l=0,r=0;
while(l<at.size())
{
while(r<at.size()&&at[r].l==at[l].l)
{
if(us[id]==0)
{
us[id]=1;
to[id].clear();
in[id]=0;
}
if(us[at[r].r]==0)
{
us[at[r].r]=1;
to[at[r].r].clear();
in[at[r].r]=0;
}
to[at[r].r].push_back(id);
++in[id];
++r;
}
l=r;
int ql=l,qr=r;
while(r<at.size()&&at[r].l==at[l].l)
{
if(us[at[r].r]==0)
{
us[at[r].r]=1;
to[at[r].r].clear();
in[at[r].r]=0;
}
to[id].push_back(at[r].r);
++in[at[r].r];
++r;
}
l=ql;
r=qr;
++id;
}
}
queue<int> q;
int cnt=0,nd=0;
for(int i=0;i<id;++i)
{
if(us[i]==1)
{
++nd;
if(in[i]==0)q.push(i);
}
}
while(!q.empty())
{
int tp=q.front();
++cnt;
q.pop();
for(int i=0;i<to[tp].size();++i)
{
--in[to[tp][i]];
if(in[to[tp][i]]==0)q.push(to[tp][i]);
}
}
if(cnt==nd)puts("Yes");
else puts("No");
}
int main()
{
//__T
sol();
return 0;
}