[CF1416F] Showing Off

发布时间 2023-12-11 20:41:38作者: 灰鲭鲨

题目链接

如果把方向看做有向边,整个图是一个内向基环树。

所以考虑哪些点有可能放在基环树的非环部分上,当且仅当一个点周围有严格小于他的点。

由于图一定是二分图(黑白染色),没有奇环,所有偶环一定可以拆成二元环,所以可以看做找匹配。两个点能匹配当且仅当他们 \(s\) 相等。

发现一个周围没有严格小于他的点,必须要匹配。有的点可以参与匹配可以不参与匹配。所以可以跑有源汇上下界网络流。

// LUOGU_RID: 139219522
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9,INF=1e9;
const char ch[]="UDLR";
int T,a[N],n,m,s,t,hd[N],e_num,hx[N],p,vh[N],q[N],l,r,b[N],v[N],g[N],in[N],ans;
struct edge{
	int v,nxt,f;
}e[N<<4];
void add_edge(int u,int v,int f)
{
//	printf("%d %d %d\n",u,v,f);
	e[++e_num]=(edge){v,hd[u],f};
	hd[u]=e_num;
	e[++e_num]=(edge){u,hd[v],0};
	hd[v]=e_num;
}
int bfs()
{
	for(int i=0;i<=t;i++)
		vh[i]=hd[i],v[i]=0;
	v[q[l=r=1]=s]=1;
	while(l<=r)
	{
		for(int i=hd[q[l]];i;i=e[i].nxt)
			if(e[i].f&&!v[e[i].v])
				v[q[++r]=e[i].v]=v[q[l]]+1;
		++l;
	}
	return v[t];
}
int dfs(int x,int fl)
{
	if(x==t)
		return fl;
	int k;
	for(int&i=vh[x];i;i=e[i].nxt)
	{
		if(v[e[i].v]==v[x]+1&&e[i].f&&(k=dfs(e[i].v,min(fl,e[i].f))))
		{
			e[i].f-=k,e[i^1].f+=k;
			return k;
		}
	}
	return 0;
}
int dinic()
{
	int ans=0,k;
	while(bfs())
		while(k=dfs(s,INF))
			ans+=k;
	return ans;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m),p=n*m;
		for(int i=0;i<p;i++)
			scanf("%d",a+i);
		for(int i=0;i<=p+3;i++)
			in[i]=hd[i]=0,b[i]=-1;
		ans=0;
		e_num=1;
		for(int i=0;i<p;i++)
		{
			int fl=0;
			if((i%m^i/m)&1)
			{
				if(i-m>=0&&a[i-m]==a[i])
					add_edge(i,i-m,1);
				if(i+m<p&&a[i+m]==a[i])
					add_edge(i,i+m,1);
				if(i%m&&a[i-1]==a[i])
					add_edge(i,i-1,1);
				if(i%m^m-1&&a[i+1]==a[i])
					add_edge(i,i+1,1);
			}
			if(i-m>=0&&a[i-m]<a[i])
				fl=1;
			if(i+m<p&&a[i+m]<a[i])
				fl=1;
			if(i%m&&a[i-1]<a[i])
				fl=1;
			if(i%m^m-1&&a[i+1]<a[i])
				fl=1;
			if(fl)
			{
				if((i%m^i/m)&1)
					add_edge(p,i,1);
				else
					add_edge(i,p+1,1);
			}
			else
			{
				if((i%m^i/m)&1)
					in[p]--,in[i]++;
				else
					in[p+1]++,in[i]--; 
			}
		}
		add_edge(p+1,p,INF);
		for(int i=0;i<=p+1;i++)
		{
			if(in[i]<0)
				add_edge(i,p+3,-in[i]);
			else
				add_edge(p+2,i,in[i]),ans+=in[i];
		}
		s=p+2,t=p+3;
		int k=dinic();
		if(k^ans)
		{
			puts("NO");
			continue;
		}
		int s=1;
		for(int i=0;i<p;i++)
		{
			int fl=0;
			if((i%m^i/m)&1)
			{
				if(i-m>=0&&a[i-m]==a[i])
				{
					s+=2; 
					if(e[s].f)
						b[i]=0,b[i-m]=1,g[i]=a[i]/2+(a[i]&1),g[i-m]=a[i]/2;
				}
				if(i+m<p&&a[i+m]==a[i])
				{
					s+=2;
					if(e[s].f)
						b[i]=1,b[i+m]=0,g[i]=a[i]/2+(a[i]&1),g[i+m]=a[i]/2;
				}
				if(i%m&&a[i-1]==a[i])
				{
					s+=2;
					if(e[s].f)
						b[i]=2,b[i-1]=3,g[i]=a[i]/2+(a[i]&1),g[i-1]=a[i]/2;
				}
				if(i%m^m-1&&a[i+1]==a[i])
				{
					s+=2;
					if(e[s].f)
						b[i]=3,b[i+1]=2,g[i]=a[i]/2+(a[i]&1),g[i+1]=a[i]/2;
				}
			}
			if(i-m>=0&&a[i-m]<a[i])
				fl=1;
			if(i+m<p&&a[i+m]<a[i])
				fl=1;
			if(i%m&&a[i-1]<a[i])
				fl=1;
			if(i%m^m-1&&a[i+1]<a[i])
				fl=1;
			if(fl)
				s+=2;
		}
		for(int i=0;i<p;i++)
		{
			if(b[i]==-1)
			{
				if(i-m>=0&&a[i-m]<a[i])
					b[i]=0,g[i]=a[i]-a[i-m];
				else if(i+m<p&&a[i+m]<a[i])
					b[i]=1,g[i]=a[i]-a[i+m];
				else if(i%m&&a[i-1]<a[i])
					b[i]=2,g[i]=a[i]-a[i-1];
				else if(i%m^m-1&&a[i+1]<a[i])
					b[i]=3,g[i]=a[i]-a[i+1];
			}
		}
		puts("YES");
		for(int i=0;i<p;i++)
		{
			printf("%d ",g[i]);
			if(i%m==m-1)
				puts("");
		}
		for(int i=0;i<p;i++)
		{
			printf("%c ",ch[b[i]]);
			if(i%m==m-1)
				puts("");
		}
	}
}