二分图!
一只变色龙与另外的变色龙颜色相同只可能有三种情况——喜欢,被喜欢和原颜色一样
我们将这样的变色龙对连上边,那么因为性别不同的限定,一定是一个二分图
这样可以二分,若加入(u)后颜色数不变那么这里面一定存在可以连边的变色龙对
我们可以黑白染色然后分开二分,这样原集合大小即为颜色数
得到之后,每个点再做两次即可找到喜欢的对象,排除后就剩下颜色相同的了
#include "chameleon.h"
#include<bits/stdc++.h>
using namespace std;
namespace mine{
const int N=1e5+4;
#define vi vector<int>
vi e[N],ask;
int n,col[N],v[2][N],vc[2],pre[N];
bool b[N],use[N];
void dfs(int x,int c){
col[x]=c;
for(auto v:e[x])
if(col[v]==-1)dfs(v,c^1);
}
inline void getcol(int i){
memset(col+1,-1,n<<2);
for(int j=1;j<i;j++)
if(col[j]==-1)dfs(j,0);
memset(vc,0,8);
for(int j=1;j<i;j++)v[col[j]][++vc[col[j]]]=j;
}
inline bool ck(int p,int l,int r,int i){
ask.clear();ask.push_back(i);
for(int j=l;j<=r;j++)
if(!b[v[p][j]])ask.push_back(v[p][j]);
return Query(ask)<ask.size();
}
int query(int p,int l,int r,int i){
if(l==r)return v[p][l];
int mid=l+r>>1;
return ck(p,l,mid,i)?query(p,l,mid,i):query(p,mid+1,r,i);
}
inline void solve(int nn){
n=nn<<1;
for(int i=1,x;i<=n;i++){
getcol(i);
memset(b+1,0,n);
for(int o=0;o<2;o++)
for(;ck(o,1,vc[o],i);){
x=query(o,1,vc[o],i);
e[i].push_back(x);
e[x].push_back(i);
b[x]=1;
}
}
ask.resize(3);
for(int i=1,x;i<=n;i++){
if(e[i].size()==1){
if(use[i])continue;
Answer(i,e[i][0]);
use[i]=use[e[i][0]]=1;
continue;
}
ask[0]=i;
ask[1]=e[i][0];ask[2]=e[i][1];x=Query(ask);
if(x==1){
swap(e[i][2],e[i][0]);
pre[e[i][0]]=i;
continue;
}
ask[2]=e[i][2];x=Query(ask);
if(x==1){
swap(e[i][1],e[i][0]);
pre[e[i][0]]=i;
continue;
}
pre[e[i][0]]=i;
}
for(int i=1,x;i<=n;i++){
if(use[i])continue;
if(pre[i]==e[i][1])x=e[i][2];
else x=e[i][1];
Answer(i,x);
use[i]=use[x]=1;
}
}
}
void Solve(int N){
mine::solve(N);
}