Codeforces 1499G - Graph Coloring(带权并查集+欧拉回路)
一道非常神仙的题 %%%%%%%%%%%%
首先看到这样的设问,做题数量多一点的同学不难想到这个题。事实上对于此题而言,题面中那个“Classical and Easy”的问题就是那题的弱化版,具体来说,借鉴那题的思路,我们考虑建立一个虚点 \(V\),然后对于所有度为奇数的点 \(x\),我们连一条 \(x\) 与 \(V\) 之间的双向边,然后跑欧拉回路。对于每一条原二分图中的边,假设其左部点为 \(x\),右部点为 \(y\),那么如果边 \((x,y)\) 在欧拉回路上的方向为 \(x\to y\) 那么我们给这条边染蓝,否则我们给这条边染红,不难发现这样每个点的 \(|r(x)-b(x)|\) 之和达到了理论下界,也就是 \(\sum\limits_{x}[deg_x\text{ is odd}]\)。
然后我就企图直接对着这个版本解决此题,想着怎么用 set 维护每一个环,怎么启发式合并,然后发现复杂度爆炸,心态也随之爆炸……
事实上,对于此题多组询问的版本而言,如果直接这么做那么会牵扯到虚点加边删边的问题,会导致问题变得异常麻烦。因此考虑怎样不建虚点来解决这个问题,显然对于原来包含虚点的图而言,如果我们在遍历包含虚点的连通块遍历到了一个包含虚点的环 \(V\to v_1\to v_2\to\cdots\to v_k\to V\),那么如果我们把 \(V\) 删掉,那就会得到一个欧拉路径,因此如果我们不建虚点,那么问题即可以转化为,要找到 \(C=\sum\limits_{x}[deg_x\text{ is odd}]\) 个欧拉路径与一些环,并将这些路径与环上的边定向。
考虑怎么维护这些环,不难发现我们加入一条边时,如果存在某两条路径分别以这条边的两个端点为端点,那么我们就要将这两条路径并起来。看到这个“并”,我们可以很自然地想到并查集维护每条路径中边的集合。不过注意到这里涉及到路径的定向问题,因此我们不能使用普通的并查集——我们需要带权并查集。具体来说,对于一条边我们记其为 \(0\) 表示这条边方向是由左部点连到右部点,\(1\) 则反过来。那么当我们加入一条边 \((x,y)\) 时:
- 如果 \(x,y\) 都不是某条边的端点,那么我们就令新加入的这条边单独成一个集合,权值 \(0/1\) 皆可。
- 如果 \(x,y\) 中恰好有一个是某条边的端点,不妨设 \(x\) 是某条边的端点,如果与 \(x\) 相连的路径上的边的权值为 \(1\),那么令新加入的这条边的权值为 \(0\),否则令新加入的边的权值为 \(1\),然后将两个集合并起来即可。
- 如果 \(x,y\) 都是某条边的端点,这种 case 稍微有点麻烦。如果与 \(x,y\) 直接相连的两条边的权值相同,那么我们就令 \((x,y)\) 的权值为与 \(x\) 相连的边的权值异或一,然后将三个集合并起来。否则我们就将 \(y\) 所在路径中所有边的权值 flip 一下,然后还是令 \((x,y)\) 权值为与 \(x\) 相连的边的权值异或一,将三个集合并起来即可。
u1s1 在做这道题之前我甚至还不会带权并查集(主要是当时 2 years ago 没认真学,大概老师讲这东西的时候我在打游戏),主要思想大概就对于一个并查集,我们定义 \(x\) 点的权值为 \(w_x\),那么我们不维护 \(w_x\),instead 我们维护一个 \(w’_x\),满足 \(w_x\) 等于 \(x\) 到根节点路径上所有点的 \(w’\) 的和(或异或和、或 \(\min\),取决于你定义了啥运算),那么在路径压缩的时候,我们考虑先遍历其父亲 \(f\),那么在遍历完父亲之后,父亲的 \(w’\) 值就是父亲真正的的 \(w\) 值减去根节点的 \(w\) 值,那么我们就直接令 \(x\) 的父亲为根节点,然后令 \(x\) 的 \(w’\) 值为父亲此时的 \(w’\) 值加上 \(x\) 原来的 \(w’\) 值即可,这样查询一个点真正的 \(w\) 值就可以拿 \(x\) 在路径压缩后的 \(w’\) 与根节点的 \(w\) 相加,将一个连通块中所有点的权值加上(或异或上)某个数 \(x\) 就直接令该连通块根节点的权值加上(或异或上)\(x\) 即可,这个异常好懂(
时间复杂度 \(\mathcal O((n+q)\log n)\)。
const int MAXN=4e5;
const int MOD=998244353;
int n1,n2,m,mm,pw2[MAXN+5],tag[MAXN+5],f[MAXN+5],res=0,sum[MAXN+5][2];
int find(int x){
if(!f[x]) return x;if(!f[f[x]]) return f[x];
int fx=find(f[x]);tag[x]^=tag[f[x]];return f[x]=fx;
}
bool ask(int x){if(!f[x]) return tag[x];int fx=find(x);/*printf("%d %d\n",tag[fx],tag[x]);*/return tag[fx]^tag[x];}
void rev(int x){
// printf("reverse %d\n",x);
x=find(x);res=(res-sum[x][tag[x]]+MOD)%MOD;
tag[x]^=1;res=(res+sum[x][tag[x]])%MOD;
}
void merge(int x,int y){
x=find(x);y=find(y);if(x==y) return;f[x]=y;
// printf("merge %d %d\n",x,y);
res=(res-sum[x][tag[x]]+MOD)%MOD;res=(res-sum[y][tag[y]]+MOD)%MOD;
sum[y][tag[y]]=(sum[y][tag[y]]+sum[x][tag[x]])%MOD;
sum[y][tag[y]^1]=(sum[y][tag[y]^1]+sum[x][tag[x]^1])%MOD;
tag[x]^=tag[y];res=(res+sum[y][tag[y]])%MOD;
}
int con[MAXN+5];
void dealins(int x,int y){
int id=++mm;sum[id][0]=pw2[id];res=(res+pw2[id])%MOD;
if(!con[x]&&!con[y]) return con[x]=con[y]=id,void();
// printf("ins %d %d\n",x,y);
if(!con[x]) swap(x,y);
if(!con[y]){
// printf("%d %d\n",x,y);
if(!ask(con[x])) rev(id);//printf("%d\n",res);
merge(id,con[x]);con[x]=0;con[y]=id;
} else {
if(ask(con[x])!=ask(con[y])) rev(con[y]);
if(!ask(con[x])) rev(id);
merge(id,con[x]);merge(id,con[y]);con[x]=con[y]=0;
}
}
void prt_color(){
int cnt=0;
for(int i=1;i<=mm;i++) if(!ask(i)) cnt++;
printf("%d\n",cnt);
for(int i=1;i<=mm;i++) if(!ask(i)) printf("%d ",i);
printf("\n");
}
int main(){
scanf("%d%d%d",&n1,&n2,&m);
pw2[0]=1;for(int i=1;i<=MAXN;i++) pw2[i]=(pw2[i-1]<<1)%MOD;
for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),dealins(u,v+n1);
int qu;scanf("%d",&qu);
while(qu--){
int opt;scanf("%d",&opt);
if(opt==1){
int u,v;scanf("%d%d",&u,&v);
dealins(u,v+n1);printf("%d\n",res);
} else prt_color();
fflush(stdout);
}
return 0;
}
/*
2 2 2
1 1
2 2
2
1 1 2
2
*/
Codeforces 1499G - Graph Coloring(带权并查集+欧拉回路)的更多相关文章
- Codeforces Educational Codeforces Round 5 C. The Labyrinth 带权并查集
C. The Labyrinth 题目连接: http://www.codeforces.com/contest/616/problem/C Description You are given a r ...
- Codeforces Round #181 (Div. 2) B. Coach 带权并查集
B. Coach 题目连接: http://www.codeforces.com/contest/300/problem/A Description A programming coach has n ...
- codeforces 687D Dividing Kingdom II 带权并查集(dsu)
题意:给你m条边,每条边有一个权值,每次询问只保留编号l到r的边,让你把这个图分成两部分 一个方案的耗费是当前符合条件的边的最大权值(符合条件的边指两段点都在一个部分),问你如何分,可以让耗费最小 分 ...
- CodeForces - 687D: Dividing Kingdom II (二分图&带权并查集)
Long time ago, there was a great kingdom and it was being ruled by The Great Arya and Pari The Great ...
- Codeforces 1156D 带权并查集
题意:给你一颗树,树边的权值可能是0或1,问先走0边,再走1边,或者只走1边的路径有多少条? 思路:对于一个点,假设通过0边相连的点一共有x个(包括自己),通过1边相连的有y个(包括自己),那么对答案 ...
- Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) C. Destroying Array 带权并查集
C. Destroying Array 题目连接: http://codeforces.com/contest/722/problem/C Description You are given an a ...
- D. The Door Problem 带权并查集
http://codeforces.com/contest/776/problem/D 注意到每扇门都有两个东西和它连接着,那么,如果第i扇门的状态是1,也就是已经打开了,那么连接它的两个按钮的状态应 ...
- POJ 1703 Find them, Catch them(带权并查集)
传送门 Find them, Catch them Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 42463 Accep ...
- [NOIP摸你赛]Hzwer的陨石(带权并查集)
题目描述: 经过不懈的努力,Hzwer召唤了很多陨石.已知Hzwer的地图上共有n个区域,且一开始的时候第i个陨石掉在了第i个区域.有电力喷射背包的ndsf很自豪,他认为搬陨石很容易,所以他将一些区域 ...
随机推荐
- javascript-jquery对象的其他处理
一.对元素进行遍历操作 如果要遍历一个jquery对象,对其中每个匹配元素进行相应处理,那么可以使用each()方法. $("div").each(function(index,e ...
- Java:ConcurrentHashMap类小记-3(JDK8)
Java:ConcurrentHashMap类小记-3(JDK8) 结构说明 // 所有数据都存在table中, 只有当第一次插入时才会被加载,扩容时总是以2的倍数进行 transient volat ...
- VS2017+QT5.12.10+QGIS3.16环境搭建及开发全流程
题记:大力发展生产力,助力高效采集.(转载请注明出处https://www.cnblogs.com/1024bytes/p/15477374.html) 本篇随笔分为五个部分: 一.获取QGIS3.1 ...
- str数组
- C语言零基础入门难发愁,那就快来看看这篇基础整理资料吧
C语言程序的结构认识 用一个简单的c程序例子,介绍c语言的基本构成.格式.以及良好的书写风格,使小伙伴对c语言有个初步认识. 例1:计算两个整数之和的c程序: #include main() { in ...
- 21.7.1 test
\(NOI\) 模拟赛 呜呜呜 \(\cdots\cdots\) \(T1\) 类似哈夫曼编码,虽然没学过但是我依然画出了二叉树,然后尝试树形dp,并且最后还抓住了一个优化!让我兴奋地以为自己能赛时A ...
- JMeter学习记录收藏
1.如何进行一个简单的性能测试 2.JMeter各种功能名词解释,比较全 3.聚合报告分析 4.CSV文件参数化,名词解释 5.JMeter快捷键
- matlab与python scipy.signal中 freqs freqz 中w,什么时候是角频率,什么时候是真实的工程中使用的采样频率Hz,如何转化
matlab与python scipy.signal中的freqs,freqz频率分析函数,输出的w,有时候是角频率,有时候是真实频率,容易搞混,这里对比一下. 0. 精要总结: 1) freqs: ...
- 几个简单的文本处理工具:diff,patch,grep,cut,sort,tr
1:文本处理工具: 1:diff and patch : diff是比较文件或者目录的不同,主要有3个用法: diff file1 file2 :比较file1和file2的不同:diff -u ...
- loadRunner12 设置关联 获取服务端动态数据
关联:服务器返回给客户端一些动态变化的值,客户端用这些值去访问服务器,不能把这些值写死在脚本里面,而应该存放在一个变量里面. 在脚本回放过程中,客户端发出请求,通过关联函数所定义的左右边界值(也就是关 ...