Loading

【题解】CF1477D Nezzar and Hidden Permutations

神仙图论题。

给定一张无向图,对于每个点指定两个排名 \(p_i,q_i\),使得对于每条边 \((u,v)\)\((p_u-p_v)(q_u-q_v)>0\) ,也就是相对排名相同。构造两个排列 \(p,q\) 使得 \(p_i\neq q_i\) 的位置最多。

转换一下,对于每条边指定一个方向,\(p,q\) 就是这张有向图的拓扑序。

我们知道拓扑序的性质,度数为 \(n-1\) 的点在拓扑序中的位置是固定的,因为每个点必定在它前面或后面,所以我们可以一直删除这样的点直到图中不存在度数为 \(n-1\) 的点。

删点我们可以用优先队列动态维护未删除的点中度数最大的点。

新图看起来没有什么区别,但是对所有边取反后发现每个点的度数至少为 \(1\)

在反图中,如果只有两个点,任意排列都是满足条件的。

如果有三个点,则有一个中点 \(x\)。手算一下只有 \(p_x=1,q_x=3\) ,其余两点相对顺序相同时是满足条件。

在反图中删边,相当于在原图中加边,所以反图删边后构造的方案也一定成立。

现在考虑四个点的情况,大部分情况可以通过删除一条边得到两个只有两个点的情况,可以递归处理。

但是只有菊花图不能递归,但是类似于三个点的方案,我们令中心为 \(x\), 构造 \(p_x=1,q_x=4\) ,其余三点相对顺序相同即可。

这启发我们将反图割去一些边后形成若干歌互不相干的菊花图来做。

考虑依次加入每个点,假设当前加入的点为 \(u\)

如果与 \(u\) 相邻的点都不处于某个菊花中,\(u\) 与其相邻的点构成一个菊花图。

令处于某个菊花中且与 \(u\) 相邻的点为 \(v\) ,如果 \(v\) 所处的菊花大小为 \(2\) ,则加入 \(u\) 后没有影响。

否则可以将 \(v\) 与原来的中心断开,与 \(v\) 形成一个以 \(u\) 为中心的新的菊花图。

反图的边很多,考虑数据结构优化。这里的做法是开两个 set 分别维护还没有加入的节点和已经处于某个菊花图中的点。

时空复杂度 \(\mathcal{O}((n+m)\log (n+m))\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 500005
using namespace std;
int n,m,h[N],tot,in[N],v[N],a[N],b[N],idx,u[N];
struct edge{int to,nxt;}e[N<<1];
void add(int x,int y){e[++tot].nxt=h[x];h[x]=tot;e[tot].to=y;}
typedef pair<int,int> Pr;
priority_queue<Pr>q;set<int>s,t;
int mat[N],col,cen[N],sz[N];
vector<int>c[N];
void solve(){
	puts("No Copy");scanf("%d%d",&n,&m);
	while(!q.empty())q.pop();
	rep(i,1,n)h[i]=v[i]=in[i]=mat[i]=sz[i]=0,c[i].clear();
	tot=col=0;s.clear();t.clear();
	rep(i,1,m){
		int x,y;scanf("%d%d",&x,&y);
		add(x,y);add(y,x);in[x]++;in[y]++;
	}
	idx=0;int w=n;rep(i,1,n)q.push(make_pair(in[i],i));
	while(!q.empty()){
		int now=q.top().second;
		if(in[now]!=w-1)break;
		q.pop();a[now]=b[now]=++idx;v[now]=1;w--;
		for(int i=h[now];i;i=e[i].nxt)if(!v[e[i].to])in[e[i].to]--,q.push(make_pair(in[e[i].to],e[i].to));
		while(!q.empty()){
			Pr cur=q.top();
			if(v[cur.second]||in[cur.second]<cur.first)q.pop();
			else break;
		}
	}
	rep(i,1,n)if(!v[i])s.insert(i);
	while(s.size()){
		int x=*s.begin(),y=0;s.erase(x);
		//cout<<"ss "<<s.size()<<" "<<x<<endl;
		for(int i=h[x];i;i=e[i].nxt)u[e[i].to]=1;
		for(set<int>::iterator it=t.begin();it!=t.end();it++)if(!u[*it]){y=*it;break;}
		t.insert(x);
		if(!y){
			++col;cen[col]=x;mat[x]=col;sz[col]=1;
			for(set<int>::iterator it=s.begin();it!=s.end();){
				if(!u[*it])sz[col]++,t.insert(*it),mat[*it]=col,it=s.erase(it);
				else it++;
			}
			for(int i=h[x];i;i=e[i].nxt)u[e[i].to]=0;
		}
		else if(sz[mat[y]]==2){
			cen[mat[y]]=y;sz[mat[y]]++;mat[x]=mat[y];
			for(int i=h[x];i;i=e[i].nxt)u[e[i].to]=0;
			for(int i=h[y];i;i=e[i].nxt)u[e[i].to]=1;
			for(set<int>::iterator it=s.begin();it!=s.end();){
				if(!u[*it])sz[mat[y]]++,t.insert(*it),mat[*it]=mat[y],it=s.erase(it);
				else it++;
			}
			for(int i=h[y];i;i=e[i].nxt)u[e[i].to]=0;
		}
		else{
			sz[mat[y]]--;++col;cen[col]=x;mat[x]=mat[y]=col;sz[col]=2;
			for(set<int>::iterator it=s.begin();it!=s.end();){
				if(!u[*it])sz[col]++,t.insert(*it),mat[*it]=col,it=s.erase(it);
				else it++;
			}
			for(int i=h[x];i;i=e[i].nxt)u[e[i].to]=0;
		}
		t.insert(x);
	}
	rep(i,1,n)if(!v[i])c[mat[i]].push_back(i);
	rep(i,1,col){
		a[cen[i]]=idx+1;
		b[cen[i]]=idx+sz[i];
		for(int j=0;j<(int)c[i].size();j++)if(cen[i]!=c[i][j])b[c[i][j]]=++idx,a[c[i][j]]=idx+1;
		idx++;
	}
	rep(i,1,n)printf("%d ",a[i]);putchar('\n');
	rep(i,1,n)printf("%d ",b[i]);putchar('\n');
}
int main(){
	int T;scanf("%d",&T);
	while(T--)solve();
	return 0;
} 
posted @ 2021-10-04 17:07  7KByte  阅读(61)  评论(0编辑  收藏  举报