解析:不看tags都意识不到用图论。
一个位置对应一个节点,对于每行每列,值相同的用并查集union一起,值不相同的,值小的节点指向值大的节点。
压缩后节点的值是到该节点的最长的链的长度,可以通过拓扑排序求得。
[code]:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 1e6+5;
struct Nod{
int b,next;
void init(int b,int next){
this->b=b;this->next=next;
}
}buf[maxn<<2];
int n,m,a[maxn],b[maxn],d[maxn],deg[maxn];
int V,len,E[maxn],par[maxn];
int ord[maxn];
queue<int> que;
bool cmp(const int &i,const int &j){
return a[i] < a[j];
}
void init(){
V = n*m;
len = 0;
memset(E,-1,sizeof(E));
for(int i = 0;i < V;i++) par[i] = i;
}
int find(int x){
return par[x]==x?x:par[x]=find(par[x]);
}
void unite(int x,int y){
x = find(x),y = find(y);
if(x == y) return;
par[y] = x;
}
void add_edge(int a,int b){
buf[len].init(b,E[a]);E[a]=len++;
deg[b]++;
}
void pre_preocess(){
int i,j;
for(i = 0;i < n;i++){
for(j = 0;j < m;j++){
ord[j] = i*m+j;
}
sort(ord,ord+m,cmp);
for(j = 1;j < m;j++){
if(a[ord[j-1]]==a[ord[j]]) unite(ord[j],ord[j-1]);
}
}
for(j = 0;j < m;j++){
for(i = 0;i < n;i++){
ord[i] = i*m+j;
}
sort(ord,ord+n,cmp);
for(i = 1;i < n;i++){
if(a[ord[i-1]]==a[ord[i]]) unite(ord[i],ord[i-1]);
}
}
}
void sol(){
int i,j,u,v;
for(i = 0;i < V;i++) if(find(i)==i&°[i]==0) que.push(i);
while(!que.empty()){
u = que.front();que.pop();
for(i = E[u];i != -1;i = buf[i].next){
v = buf[i].b;
d[v] = max(d[v],d[u]+1);
if(--deg[v]==0){
que.push(v);
}
}
}
for(i = 0;i < V;i++){
printf("%d ",d[find(i)]+1);
if((i+1)%m==0) putchar('\n');
}
}
int main(){
int i,j;
scanf("%d%d",&n,&m);
init();
for(i = 0;i < n*m;i++) scanf("%d",&a[i]);
pre_preocess();
for(i = 0;i < n;i++){
for(j = 0;j < m;j++){
ord[j] = i*m+j;
}
sort(ord,ord+m,cmp);
for(j = 1;j < m;j++){
if(a[ord[j-1]]==a[ord[j]]) continue;
add_edge(find(ord[j-1]),find(ord[j]));
}
}
for(j = 0;j < m;j++){
for(i = 0;i < n;i++){
ord[i] = i*m+j;
}
sort(ord,ord+n,cmp);
for(i = 1;i < n;i++){
if(a[ord[i-1]]==a[ord[i]]) continue;
add_edge(find(ord[i-1]),find(ord[i]));
}
}
sol();
return 0;
}