You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.7 KiB
4.7 KiB
Aimai
Trip
题目描述
有 n
只猫猫在玩捉迷藏。猫猫们的编号分别为 1,2,\cdots,n
。
屋子里有 k
个房间,每个房间只能容纳一只猫猫。
每个房间有一定的属性,可以用 x_i,y_i
来表示,意为:
- 这个房间要么空着,要么容纳第
x_i
只猫猫,要么容纳第y_i
只猫猫。
现在云浅可以买下前 m
个房间给猫猫们使用。云浅想要知道,m
的值至少是多少,才能容纳所有猫猫。保证买下所有房间后一定可以容纳所有猫猫。
为了更好地帮助小可爱,你还需要输出一个方案。如果有多个可行的方案,输出任意一个即可。
输入格式
第一行两个正整数 n,k
。
第二行 k
个正整数 x_1,\cdots,x_k
,表示每个房间的第一种属性。
第三行 k
个正整数 y_1,\cdots,y_k
,表示每个房间的第二种属性。
输出格式
先输出一行一个正整数 m
表示答案。
第二行输出 m
个正整数,以空格隔开。其中,若第 i
个数为 0
则表示第 i
个房间空着不用,第 i
个数为 1
则表示分给第 x_i
只猫猫,第 i
个数为 2
则表示分给第 y_i
只猫猫。
数据范围
对于 100\%
的数据,1\le n \le 10^5,1\le k\le 2\times 10^5,1\le x_i,y_i\le n,x_i\neq y_i
。
测试点编号 | n |
k |
---|---|---|
1\sim 6 |
\le 20 |
\le 20 |
7\sim 10 |
\le 1000 |
\le 1000 |
11\sim 14 |
\le 1000 |
\le 10^5 |
15\sim 20 |
\le 10^5 |
\le 2\times 10^5 |
题解
首先二分答案,相当于只需要判定一下是否所有小可爱都能住进至少一个房间。
考虑对每个房间连边 (x_i,y_i)
,那么,所有小可爱都能住进至少一个房间,当且仅当:
- 图中的每个连通块的边数均不小于点数。
证明:若要求所有小可爱都能住进至少一个房间,显然边数必然不小于点数。
如果边数不小于点数,那么这个连通块中至少存在一个环。考虑令在环上的边所代表的房间依次给第 x_i
只小可爱,然后从这个环向外延伸出去若干条链,链上的边从环内指向环外即可。
构造方案也可以使用类似的方法。
于是就做完了,时间复杂度 O((n+k)\log k)
。
参考代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
for(;(c<'0'||c>'9');c=getchar()){if(c=='-')f=-1;}
for(;(c>='0'&&c<='9');c=getchar())x=x*10+(c&15);
return x*f;
}
const int MN=2e5+5;
int n,k;
int fr[MN],to[MN];
struct Edge{
int to,id;
Edge(int T,int I):to(T),id(I){}
Edge(){}
};
vector<Edge>G[MN];
vector<int>S;
bool vis[MN];
void getnodes(int u){
vis[u]=1;S.push_back(u);
for(auto e:G[u]){
int v=e.to,i=e.id;
if(!vis[v])getnodes(v);
}
}
vector<int>C;
int fa[MN],pre[MN],res[MN];
bool fi=0;
void findcycle(int u){
vis[u]=1;
for(auto e:G[u]){
int v=e.to,i=e.id;
if(i==pre[u])continue;
if(!vis[v]){fa[v]=u,pre[v]=i,findcycle(v);continue;}
if(fi)continue;
int x=u;
while(x!=v){
C.push_back(x),res[pre[x]]=(fr[pre[x]]==x?2:1);
x=fa[x];
}
res[i]=(fr[i]==u?1:2);fi=1;C.push_back(v);
}
}
bool chk(int m){
for(int i=1;i<=n;i++)G[i].clear();
memset(vis,0,sizeof(vis)),memset(pre,0,sizeof(pre)),memset(fa,0,sizeof(fa));
for(int i=1;i<=m;i++){
int u=fr[i],v=to[i];
G[u].push_back(Edge(v,i)),G[v].push_back(Edge(u,i));
}
for(int i=1;i<=n;i++){
if(vis[i])continue;
fi=0,C.clear();findcycle(i);
if(!fi)return 0;
}
return 1;
}
void dfs(int u){
vis[u]=1;
for(auto e:G[u]){
int v=e.to,i=e.id;
if(vis[v]||res[i]!=0)continue;
res[i]=(fr[i]==v?1:2);dfs(v);
}
}
void getans(int m){
for(int i=1;i<=n;i++)G[i].clear();
memset(vis,0,sizeof(vis)),memset(pre,0,sizeof(pre));
memset(fa,0,sizeof(fa)),memset(res,0,sizeof(res));
for(int i=1;i<=m;i++){
int u=fr[i],v=to[i];
G[u].push_back(Edge(v,i)),G[v].push_back(Edge(u,i));
}
for(int i=1;i<=n;i++){
if(vis[i])continue;
S.clear();getnodes(i);fi=0;
for(int p:S)vis[p]=0;
C.clear();findcycle(i);
for(int p:S)vis[p]=0;
for(int p:C)vis[p]=1;
for(int p:C)dfs(p);
for(int p:S)vis[p]=1;
}
for(int i=1;i<=m;i++)cout<<res[i]<<" ";puts("");
}
signed main(void){
freopen("cats.in","r",stdin);
freopen("cats.out","w",stdout);
n=read(),k=read();
for(int i=1;i<=k;i++)fr[i]=read();
for(int i=1;i<=k;i++)to[i]=read();
int L=1,R=k,ans=L;
while(L<=R){
int mid=(L+R)>>1;
if(chk(mid))R=mid-1,ans=mid;
else L=mid+1;
}
cout<<ans<<endl;
getans(ans);
return 0;
}