[CF1477D] Nezzar and Hidden Permutations

一开始看到这道题确实有种无从下手的感觉,具体说一说思考过程


  • 容易得出若 \(m = \frac{n(n-1)}{2}\),必定排列 \(p\)\(q\) 相等,思考若删掉一个限制之后会怎么样。

第一步是简单的,发现若删掉 \((l,r)\),那么只要 \(l\)\(r\) 中的元素是相邻的,那么 \(l\)\(r\) 的元素就可以交换了,也就自然而然在 \((l,r)\) 之间连了一条边。

  • 那再删一个限制呢?

如果互不影响,两两交换就可以了,但如果两个限制中的元素出现重复呢?手玩一下就会发现,若把这三个位置的元素表示成 \(y,y+1,y+2\),那可以构造出以下两个排列的元素(假定中间的元素是两个限制共用的元素):

\(p:(y+1,y,y+2)\)

\(q:(y,y+2,y+1)\)

所以我们得出:对于一个菊花图,必然存在一种方案使得两个排列相同位置的元素不相同,也就是说我们要将反图拆成多个点数 \(> 1\) 的菊花图。

  • 如何构造?

首先先把已经被限制死的点给删掉,剩下的图是不会出现单点的。

然后随便找一个生成树,我们手玩一下:

对于当前点 \(u\),设树中与它相连的点为 \(v\)

  1. \(v\) 作为菊花图的根的,直接连即可。
  2. \(v\) 所在的菊花图的大小 \(> 2\),把 \(v\) 让给 \(x\) 即可。
  3. \(v\) 所在的菊花图大小为 \(2\),把 \(x\) 加入不影响。

所以必然有解!然后就做完了。

点击查看代码
#include<bits/stdc++.h>
#define fir first
#define sec second
#define int long long
#define lowbit(x) x&(-x)
#define mkp(a,b) make_pair(a,b)
using namespace std;
typedef pair<int,int> pir;
inline int read(){
	int x=0,f=1; char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1; c=getchar();}
	while(isdigit(c)){x=x*10+(c^48); c=getchar();}
	return x*f;
}
const int inf=1e18,N=5e5+5;
int T;
int n,m;
int du[N];
int p[N],q[N];
vector<int> ed[N],re[N];
queue<int> qu;
set<int> s;
map<pir,int> mp;
inline void dfs(int x,int fa){
    for(auto it=s.begin();it!=s.end();it++){
        int v=*it;
        if(mp.find(mkp(x,v))==mp.end()){
            re[x].push_back(v);
            re[v].push_back(x);
        }
    }
    for(auto v:re[x]) if(v!=fa) s.erase(v);
    for(auto v:re[x]) if(v!=fa) dfs(v,x);
}
int vis[N],rt[N],siz[N],tot;
inline void dfs2(int x,int fa){
    if(!vis[x]){
        int fl=0;
        for(auto v:re[x]) fl|=(vis[v]==0);
        if(fl){
            vis[x]=++tot;
            rt[tot]=x;
            siz[tot]=1;
            for(auto v:re[x]) if(!vis[v]) vis[v]=tot,siz[tot]++;
        }
        else{
            for(auto v:re[x]){
                if(rt[vis[v]]==v){
                    vis[x]=vis[v];
                    siz[vis[v]]++;
                    break;
                }
                if(siz[vis[v]]>2){
                    siz[vis[v]]--;
                    vis[x]=vis[v]=++tot;
                    rt[tot]=x;
                    siz[tot]=2;
                    break;
                }
                rt[vis[v]]=v;
                vis[x]=vis[v];
                siz[vis[v]]++;
                break;
            }
        }
    }
    for(auto v:re[x]) if(v!=fa) dfs2(v,x);
}
inline void clear(){
    mp.clear();
    for(int i=1;i<=n;i++) ed[i].clear(),re[i].clear(),du[i]=0;
    s.clear();
    for(int i=1;i<=n;i++) vis[i]=siz[i]=rt[i]=p[i]=q[i]=0;
    tot=0;
}
inline void solve(){
    clear();
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        ed[u].push_back(v);
        ed[v].push_back(u);
        mp[mkp(u,v)]=mp[mkp(v,u)]=1;
        du[u]++,du[v]++;
    }
    for(int i=1;i<=n;i++) s.insert(i);
    int cnt=0;
    for(int i=1;i<=n;i++) if(du[i]==n-1) qu.push(i),s.erase(i);
    while(!qu.empty()){
        int x=qu.front();
        qu.pop();
        p[x]=q[x]=++cnt;
        for(auto v:ed[x]){
            du[v]--;
            if((s.find(v)!=s.end())&&du[v]>=n-cnt-1){
                s.erase(v);
                qu.push(v);
            }
        }
    }
    for(int i=1;i<=n;i++) if(s.find(i)!=s.end()){
        s.erase(i);
        dfs(i,0);
    }
    for(int i=1;i<=n;i++) if(!vis[i]&&!p[i]) dfs2(i,0);
    for(int i=1;i<=tot;i++){
        int x=rt[i];
        p[x]=++cnt;
        for(auto v:re[x]){
            if(vis[v]!=i) continue;
            q[v]=cnt,p[v]=++cnt;
        }
        q[x]=cnt;
    }
    for(int i=1;i<=n;i++) cout<<p[i]<<' ';
    puts("");
    for(int i=1;i<=n;i++) cout<<q[i]<<' ';
    puts("");
}
signed main(){
    T=read();
    while(T--) solve();
}
posted @ 2024-12-19 21:39  ~Cyan~  阅读(14)  评论(0)    收藏  举报