zoukankan      html  css  js  c++  java
  • CF1499G Graph Coloring 题解

    Codeforces
    Luogu

    Description.

    给定一个二分图,给边染色。
    使得 \(\sum|\text{black}(u)-\text{white}(u)|\) 最小。
    其中 \(\text{black}(u)\)\(\text{white}(u)\) 分别表示和 \(u\) 相邻黑/白边的数量。
    支持动态加边,查询哈希值 \(\sum_{e|\text{col}(e)=\text{white}}2^{\text{id}(e)}\bmod 998244353\),有不超过 \(10\) 次询问要求查询哈希值对应的染色方案。

    Solution.

    首先考虑一组询问。
    上限显然是 \(\sum[\deg_i\bmod 2]\),而我们肯定可以达到这个上界。
    具体的,因为是二分图,所以所有环都是偶环。
    我们找到一个偶环,然后相邻一黑一白染色。
    对于所有奇点,我们建一个虚点,让其向虚点连边,再删掉虚点。
    这样剩下的一堆链肯定构成答案。

    考虑怎么维护这个东西,可以动态维护答案。
    插入一条边只有以下三种情况

    1. 都是链的端点:如果颜色相同直接挂,否则需要反转一整条链
    2. 一端是一端不是:挂上去
    3. 都不是链的端点:新增一条链

    然后直接并查集,支持合并、打tag。
    就这个东西写了一年写地很屎最后还是调不出来参考了题解的代码实现。

    Coding.

    点击查看代码
    //Coded by Kamiyama_Shiki on 2021.11.01 {{{
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
    const int N=400005,P=998244353;int n1,n2,m,n,etc;
    inline int ksm(int x,int q=P-2) {int r=1;for(;q;q>>=1,x=1ll*x*x%P) if(q&1) r=1ll*r*x%P;return r;}
    inline void pls(int &x,int y) {(x+=y)>=P?x-=P:x;}
    int fa[N],vl[N][2],xr[N],fg[N],rs=0;
    inline int getf(int x)
    {
    	if(fa[x]==x) return x;else if(fa[fa[x]]==fa[x]) return fa[x];
    	int tp=fa[x];return fa[x]=getf(fa[x]),xr[x]^=xr[tp],fa[x];
    }
    inline void merge(int u,int v)
    {
    	int x=getf(u),y=getf(v);if(x==y) return;
    	rs=(1ll*rs+P-vl[x][xr[x]]+P-vl[y][xr[y]])%P,xr[x]^=xr[y],fa[x]=y;
    	pls(vl[y][0],vl[x][xr[x]]),pls(vl[y][1],vl[x][!xr[x]]),pls(rs,vl[y][xr[y]]);
    }
    inline void rev(int x) {x=getf(x),rs=(1ll*rs-vl[x][xr[x]]+vl[x][!xr[x]]+P)%P,xr[x]^=1;}
    inline int col(int x) {return getf(x),xr[x]^(x==getf(x)?0:xr[getf(x)]);}
    inline void ins(int x,int y,int id)
    {
    	//printf("add %d %d %d\n",x,y,id);
    	fa[id]=id,vl[id][1]=ksm(2,id),vl[id][0]=xr[id]=0;
    	if(!fg[x]&&!fg[y]) {fg[x]=fg[y]=id;return;}
    	else if(fg[x]<fg[y]) swap(x,y);
    	if(fg[x]&&!fg[y])
    	{
    		if(!col(fg[x])) rev(id);
    		merge(id,fg[x]),fg[y]=id,fg[x]=0;return;
    	}
    	if(col(fg[x])^col(fg[y])) rev(fg[x]);
    	if(!col(fg[x])) rev(id);
    	merge(fg[x],id),merge(fg[y],id),fg[x]=fg[y]=0;
    }
    inline void debug()
    {
    	vector<int>rs;for(int i=1;i<=etc;i++) if(col(i)) rs.push_back(i);
    	printf("%d ",(int)rs.size());for(auto x:rs) printf("%d ",x);putchar('\n');
    }
    int main()
    {
    	read(n1,n2,m),n=n1+n2;
    	for(int i=1,x,y;i<=m;i++) read(x,y),ins(x,y+n1,++etc);
    	int Ca;for(read(Ca);Ca--;)
    	{
    		int fg,x,y;read(fg);if(fg&1) read(x,y);
    		if(fg==2) debug();else ins(x,y+n1,++etc),printf("%d\n",rs);
    		fflush(stdout);
    	}return 0;
    }
    
  • 相关阅读:
    一个java的进销存管理系统源码阅读
    嵌入式起步
    java数据库操作有关的杂记
    VS 调试
    软件测试的原则
    黑盒测试与白盒测试
    Xmind快速入门(基本操作够用了)
    opt目录
    日志测试
    bug的前世今生
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15497299.html
Copyright © 2011-2022 走看看