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很自豪,他认为搬陨石很容易,所以他将一些区域 ...
随机推荐
- perl合并文件
使用Perl合并文件 有时需要将整个目录下的小文件合并到一个文件中,以便查阅检索 特性 整个目录完全遍历,自动存入单个文件顺序遍历文件 待合并的目录 合并后的文件内容 syscfg/test1 sys ...
- Django Model字段加密的优雅实现
早前的一篇文章Django开发密码管理表实例有写我们写了个密码管理工具来实现对密码的管理,当时加密解密的功能在view层实现,一直运行稳定所以也没有过多关注实现是否优雅的问题.最近要多加几个密码表再次 ...
- 【UE4】读写 Texture 数据
创建texture 方式一 void AActor_Assignment2::TextureFromImage_Internal( const TArray<FColor>& Sr ...
- SpringCloud-初见
目录 前言 微服务概述 微服务与微服务架构 微服务优缺点 微服务技术栈 为什么选择SpringCloud作为微服务架构 SpringCloud入门 SpringCloud和SpringBoot的关系 ...
- OO第二单元——多线程(电梯)
OO第二单元--多线程(电梯) 综述 第二单元的三次联系作业都写电梯,要求逐步提高,对于多线程的掌握也进一步加深.本次作业全部都给出了输入输出文件,也就避免了正则表达式判断输入输出是否合法的问题. 第 ...
- 【做题记录】[NOIP2016 普及组] 魔法阵
P2119 魔法阵 2016年普及组T4 题意: 给定一系列元素 \(\{X_i\}\) ,求满足以下不等式的每一个元素作为 \(a,b,c,d\) 的出现次数 . \[\begin{cases}X_ ...
- createContext 你用对了吗?
目录 前言 性能问题的根源 问题1(整体重复渲染):Provider组件包裹的子组件全部渲染 问题2(局部重复渲染):使用useContext导致组件渲染 解决方案 解决问题1 解决问题2 参考 前言 ...
- 【行人惯性导航】关于行人导航中IMU位姿推导的知识点及相关代码
IMU姿态惯性推导 最近从事行人惯性导航的研究,本人也是一个小白,其中看了很多文献,有很多个人思考很费时间的地方,撰写此随笔的目的不仅是给自己做一个笔记,也是给各位有需要的仁兄一点个人理解. 本文只关 ...
- best-time-to-buy-and-sell-stock leetcode C++
Say you have an array for which the i th element is the price of a given stock on day i. If you were ...
- cf 11B Jumping Jack(贪心,数学证明一下,,)
题意: 给一个数X. 起始点为坐标0.第1步跳1格,第2步跳2格,第3步跳3格,.....以此类推. 每次可以向左跳或向右跳. 问最少跳几步可以到坐标X. 思路: 假设X是正数. 最快逼近X的方法是不 ...