[CF2147H] Maxflow GCD Coloring 题解
l1ng21y12026 · · 题解
- [CF2147H] Maxflow GCD Coloring:最小割树 + 高斯消元 / 构造。
观察到这题很复杂,我们猜测答案很小,不妨猜
对于
对于
如果图是一个欧拉图,那么对于每个最小割
同时这也是必要条件,如果存在
那么相当于让我们将图分为两个导出欧拉子图。
令
即在导出子图中每个点度数为偶:
考虑证明这个异或方程组一定有解。注意此时方程中的
考虑反证法,令
无解即存在点集
考虑消元时,将
只剩下若干形如
高斯消元即可。对于第
还有一种构造解法,比较需要脑子。考虑增 / 减量构造,将图分为两个导出欧拉子图。
首先,取一个图中度数为奇数的点
重复这个过程直到图中只有度数为偶数的点。将图中剩余点分入集合
然后,将删去的点依次加入,并将之前多两两连的边撤销。
对于被删去的点
我们将
考虑没有加入
综上,最后
代码使用高斯消元方法。
#include<bits/stdc++.h>
#define rg register int
#define fo(i,l,r) for(rg i=(l);i<=(r);i++)
#define dfo(i,r,l) for(rg i=(r);i>=(l);i--)
#define fe(i,x) for(rg i=hd[x];i;i=nex[i])
#define frein freopen("in.txt","r",stdin);
#define freout freopen("out.txt","w",stdout);
#define fre(p) freopen(#p".in","r",stdin),freopen(#p".out","w",stdout);
#define eb emplace_back
#define pii pair<int,int>
#define mkp make_pair
#define fir first
#define sec second
#define vi vector<int>
#define db double
#define i8 __int128
#define ll long long
using namespace std;
bool deb=1;
void ck_(){cerr<<"\n";}
template<typename T,typename ...R>
void ck_(T x,R... y){if(!deb)return;cerr<<x<<" ";ck_(y...);}
void Bz_(){if(deb)cerr<<"------------------------------\n";}
#define ck(x...) ck_(x)
#define Bz Bz_()
#define outa(l,r,a) {if(deb){fo(II,l,r)cerr<<a[II]<<" ";cerr<<"\n";}}
auto St=chrono::high_resolution_clock::now();
#define gettime() (chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now()-St).count())
const int N=55,M=6005;
int Task,n,m,x,y,z,Q;
struct nd{int p,v;};vector<nd>e[N];
struct edge{int x,y,z;}eg[M];
int sum=1,to[M],nex[M],hd[N],ef[M];
void ado(int x,int y,int f){to[++sum]=y,nex[sum]=hd[x],hd[x]=sum,ef[sum]=f;}
void add(int x,int y,int f){ado(x,y,f),ado(y,x,0);}
#define inf 1e9
int S,T,p[N];
int t,w,q[M<<5],dis[N],cur[N];
bool bfs()
{
fo(i,1,n)dis[i]=inf,cur[i]=hd[i];
q[t=w=1]=S,dis[S]=0;
while(t<=w)
{
int x=q[t++];
fe(i,x)if(ef[i]&&dis[to[i]]==inf)
{
dis[to[i]]=dis[x]+1,q[++w]=to[i];
}
}
return dis[T]!=inf;
}
int dfs(int x,int fl)
{
if(x==T)return fl;
int s=0,t;
for(rg i=cur[x];i&&fl;i=nex[i])
{
cur[x]=i;
if(ef[i]&&dis[to[i]]==dis[x]+1)
{
t=dfs(to[i],min(fl,ef[i]));
if(t==0)dis[to[i]]=-1;
ef[i]-=t,ef[i^1]+=t,s+=t,fl-=t;
}
}
return s;
}
int dinic(int SS,int TT)
{
S=SS,T=TT;sum=1;
fo(i,1,n)hd[i]=0;
fo(i,1,m)add(eg[i].x,eg[i].y,eg[i].z),add(eg[i].y,eg[i].x,eg[i].z);
int ans=0;
while(bfs())ans+=dfs(S,inf);
return ans;
}
void wk(int l,int r)
{
if(l>=r)return;
int mxf=dinic(p[l],p[r]);
e[p[l]].eb(nd{p[r],mxf}),e[p[r]].eb(nd{p[l],mxf});
vi le,ri;
fo(i,l,r)
{
if(dis[p[i]]==inf)le.eb(p[i]);
else ri.eb(p[i]);
}
int i=l,md;
for(int o:le)p[i++]=o;md=i;
for(int o:ri)p[i++]=o;
wk(l,md-1),wk(md,r);
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int ans;
void getans(int o,int x,int fa,int d)
{
if(o!=x)ans=ans==0?d:gcd(ans,d);
for(nd y:e[x])if(y.p!=fa)getans(o,y.p,x,min(d,y.v));
}
bitset<N>b[N];
void gauss()
{
fo(k,1,n)
{
int x=0;
fo(i,k,n)if(b[i][k]==1)x=i;
swap(b[k],b[x]);
fo(i,1,n)if(i!=k&&b[i][k]==1)b[i]^=b[k];
}
}
void solve()
{
cin>>n>>m;
fo(i,1,m)cin>>x>>y>>z,eg[i]=edge{x,y,z};
fo(i,1,n)e[i].clear();
fo(i,1,n)p[i]=i;wk(1,n);
ans=0;
fo(i,1,n)getans(i,i,0,inf);
if(ans>=2||ans==0)
{
cout<<"1\n"<<n<<"\n";
fo(i,1,n)cout<<i<<" ";cout<<"\n";
return;
}
fo(i,1,n)b[i].reset();
fo(i,1,m)if(eg[i].z&1)
{
x=eg[i].x,y=eg[i].y;
b[x].flip(x),b[x].flip(y),b[x].flip(0);
b[y].flip(y),b[y].flip(x),b[y].flip(0);
}
gauss();
int c0=0,c1=0;
fo(i,1,n)b[i][0]?++c1:++c0;
cout<<"2\n";
cout<<c0<<"\n";fo(i,1,n)if(b[i][0]==0)cout<<i<<" ";cout<<"\n";
cout<<c1<<"\n";fo(i,1,n)if(b[i][0]==1)cout<<i<<" ";cout<<"\n";
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>Task;
while(Task--)solve();
return 0;
}