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

    一、题目

    点此看题

    二、解法

    首先考虑定边怎么做,考虑构造得到最小解,我们先把所有环删掉,然后原图就剩下的若干条路径,我们把度为奇数的点作为某一条路径的端点,度为偶数的点不作为端点,那么答案就取到了下界:(sum[deg[u]\%2=1])

    题目要求动态加边,并且强制在线,那就真的只能加边了呗,我们讨论一个新加边的两个节点的情况:

    • 如果都不是路径的端点,那么可以直接把这条边当成路径加进去。
    • 如果其中一个是路径的端点,那么把这条边接到路径上面去。
    • 如果都是路径的端点,那么考虑把这两条路径连起来,考虑连在这两个点上的两条边如果颜色相同,那么直接连上去;如果颜色不同,那么翻转其中一条路径的所有边的颜色。

    主要问题是维护翻转操作,我们把边看成点,考虑用带权并查集来维护。众所周知带权并查集是可以打标记的,并查集中我们用到根路径上的所有标记 (rev) 的异或和来表示这条边的颜色。

    然后每个点维护 (sum[0/1]) 表示蓝边和红边的总和,翻转的时候可以不用交换它们而直接用 (rev) 作为下标。因为翻转只会翻转根,我们在翻转的时候维护一下哈希值即可,时间复杂度 (O(nalpha))

    三、总结

    最小化问题可以考虑构造出答案下界(( t construction force) 最喜欢这么考了,我总是想不到)

    有整体标记和合并问题可以考虑带权并查集(这个权的含义实际上就是标记)

    #include <cstdio>
    #include <iostream>
    using namespace std;
    const int M = 400005;
    const int MOD = 998244353;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,q,id,hs,fa[M],a[M],rev[M],to[M],sum[M][2];//0:bule 1:red
    int find(int x)
    {
    	if(fa[x]==x) return x;
    	if(fa[fa[x]]==fa[x]) return fa[x];
    	int t=find(fa[x]);
    	rev[x]^=rev[fa[x]];
    	return fa[x]=t;
    }
    void tag(int x)
    {
    	x=find(x);
    	hs=(hs-sum[x][rev[x]^1]+MOD)%MOD;
    	rev[x]^=1;
    	hs=(hs+sum[x][rev[x]^1])%MOD;
    }
    int col(int x)
    {
    	if(x==fa[x]) return rev[x];
    	int t=find(x);
    	return rev[x]^rev[t];
    }
    void merge(int x,int y)
    {
    	x=find(x);y=find(y);
    	if(x==y) return ;
    	sum[y][rev[y]]=(sum[y][rev[y]]+sum[x][rev[x]])%MOD;
    	sum[y][rev[y]^1]=(sum[y][rev[y]^1]+sum[x][rev[x]^1])%MOD;
    	fa[x]=y;rev[x]^=rev[y];
    }
    void link(int x,int y)
    {
    	id++;fa[id]=id;
    	sum[id][0]=a[id]=(a[id-1]<<1)%MOD;
    	//case1: a brand new path
    	if(!to[x] && !to[y])
    	{
    		to[x]=to[y]=id;
    		return ;
    	}
    	//case2: have a same vertex
    	if(!to[x]) swap(x,y);
    	if(!to[y])
    	{
    		if(!col(to[x])) tag(id);
    		merge(to[x],id);
    		to[x]=0;to[y]=id;
    		return ;
    	}
    	//case3: have two vertex
    	if(col(to[x])!=col(to[y])) tag(to[x]);
    	if(!col(to[x])) tag(id);
    	merge(to[x],id);
    	merge(to[y],id);
    	to[x]=to[y]=0;
    }
    signed main()
    {
    	n=read();m=read();q=read();
    	a[0]=1;
    	for(int i=1;i<=q;i++)
    	{
    		int u=read(),v=read();
    		link(u,v+n);
    	}
    	q=read();
    	while(q--)
    	{
    		int op=read();
    		if(op==1)
    		{
    			int u=read(),v=read();
    			link(u,v+n);
    			printf("%d
    ",hs);
    		}
    		else
    		{
    			int ans=0;
    			for(int i=1;i<=id;i++)
    				if(col(i)) ans++;
    			printf("%d",ans);
    			for(int i=1;i<=id;i++)
    				if(col(i)) printf(" %d",i);
    			puts("");
    		}
    		fflush(stdout);
    	}
    }
    
  • 相关阅读:
    english note(6.3 to 6.8)
    english note(6.2 to 5.30)
    Lambda表达式
    Python Software Foundation
    eval(input())
    北航操作系统实验2019:Lab4-1代码实现参考
    北航操作系统实验2019:Lab4-1流程梳理
    面向对象设计与构造2019 第二单元总结博客作业
    面向对象设计与构造2019 第一单元总结博客作业
    Java代码度量分析工具:Designite简介
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15041937.html
Copyright © 2011-2022 走看看