Codeforces 651E Table Compression 拓扑序

题意:给出n*m矩阵a,要求把矩阵a压缩成矩阵b.b的元素尽量小.并且满足下列条件
若a[i][j]<=a[i][k],则b[i][j]<=b[i][k]
若a[i][j]<=a[p][j] 则b[i][j]<=b[p][j]
 1<=n,m<=1e6 && n*m<=1e6

a[i][j]和其同行同列有着拓扑序(谁比谁小连一条有向边),则从a[i][j]最小的开始填,每次维护行/列的最值即可.

但同行同列中若有相同的? 把这些同行同列相同的数用放到同一个集合,并查集维护要取的值即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+20;
vector< vector<int> >res;
struct point{
	int x,y;
	point(){}
	point(int a,int b):x(a),y(b){}
	bool operator < (const point &t)const{
		return x==t.x? y<t.y:x<t.x;
	}
};
pair<int,point> p[N];
int fa[N],mx[N],my[N],mi[N],la[N];
void init(int n){for(int i=0;i<n;i++) fa[i]=i;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void Union(int x,int y)
{	
	int fx=find(x),fy=find(y);
	fa[fx]=fy;
}
int main()
{
	int n,m,x;
	cin>>n>>m;
	res.resize(n);
	for(int i=0;i<n;i++)
		res[i].resize(m);
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
		{
			scanf("%d",&x);
			p[i*m+j]=make_pair(x,point(i,j));	
		}
	sort(p,p+n*m);
	init(n*m);
	memset(la,-1,sizeof(la));
	int l=0,r=0;
	while(l<n*m)
	{
		while(r<n*m && p[l].first==p[r].first) r++;
		for(int i=l;i<r;i++)
		{
			if(i>l && p[i].second.x==p[i-1].second.x)
				Union(i,i-1);	
			if(~la[p[i].second.y])
				Union(i,la[p[i].second.y]);
			la[p[i].second.y]=i;
		}
		for(int i=l;i<r;i++)
		{
			int t=find(i);
			mi[t]=max(mi[t],mx[p[i].second.x]);
			mi[t]=max(mi[t],my[p[i].second.y]);
		}
		for(int i=l;i<r;i++)
		{
			int t=find(i);
			int x=p[i].second.x,y=p[i].second.y;
			res[x][y]=mi[t]+1;
			mx[x]=mi[t]+1;
			my[y]=mi[t]+1;
		}
		while(l<r)
			la[p[l++].second.y]=-1;	
	}
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			printf("%d%c",res[i][j],j==m-1?'\n':' ');
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值