Codeforces 题面传送门 & 洛谷题面传送门

一道非常神仙的题 %%%%%%%%%%%%

首先看到这样的设问,做题数量多一点的同学不难想到这个题。事实上对于此题而言,题面中那个“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(带权并查集+欧拉回路)的更多相关文章

  1. 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 ...

  2. Codeforces Round #181 (Div. 2) B. Coach 带权并查集

    B. Coach 题目连接: http://www.codeforces.com/contest/300/problem/A Description A programming coach has n ...

  3. codeforces 687D Dividing Kingdom II 带权并查集(dsu)

    题意:给你m条边,每条边有一个权值,每次询问只保留编号l到r的边,让你把这个图分成两部分 一个方案的耗费是当前符合条件的边的最大权值(符合条件的边指两段点都在一个部分),问你如何分,可以让耗费最小 分 ...

  4. 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 ...

  5. Codeforces 1156D 带权并查集

    题意:给你一颗树,树边的权值可能是0或1,问先走0边,再走1边,或者只走1边的路径有多少条? 思路:对于一个点,假设通过0边相连的点一共有x个(包括自己),通过1边相连的有y个(包括自己),那么对答案 ...

  6. 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 ...

  7. D. The Door Problem 带权并查集

    http://codeforces.com/contest/776/problem/D 注意到每扇门都有两个东西和它连接着,那么,如果第i扇门的状态是1,也就是已经打开了,那么连接它的两个按钮的状态应 ...

  8. POJ 1703 Find them, Catch them(带权并查集)

    传送门 Find them, Catch them Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 42463   Accep ...

  9. [NOIP摸你赛]Hzwer的陨石(带权并查集)

    题目描述: 经过不懈的努力,Hzwer召唤了很多陨石.已知Hzwer的地图上共有n个区域,且一开始的时候第i个陨石掉在了第i个区域.有电力喷射背包的ndsf很自豪,他认为搬陨石很容易,所以他将一些区域 ...

随机推荐

  1. 【UE4 C++】简单获取名称、状态、时间、帧数、路径与FPaths

    基于UKismetSystemLibrary 获取各类名称 // Returns the actual object name. UFUNCTION(BlueprintPure, Category = ...

  2. Coursera Deep Learning笔记 逻辑回归典型的训练过程

    Deep Learning 用逻辑回归训练图片的典型步骤. 笔记摘自:https://xienaoban.github.io/posts/59595.html 1. 处理数据 1.1 向量化(Vect ...

  3. 安装多个版本的MySQL

    安装多个版本的MySQL 之前在PC机上安装了 MySQL 5.5 后续发现了窗口函数,而窗口函数是 MySQL8 以后才支持的,故在本地又安装了一个 MySQL 8 安装MySQL 5.5 进入my ...

  4. Scrum Meeting 11

    第11次例会报告 日期:2021年06月01日 会议主要内容概述: 汇报了进度,开始爆肝. 一.进度情况 我们采用日报的形式记录每个人的具体进度,链接Home · Wiki,如下记录仅为保证公开性: ...

  5. 【二食堂】Beta - Scrum Meeting 12

    Scrum Meeting 12 例会时间:5.27 20:00~20:10 进度情况 组员 当前进度 今日任务 李健 1. 知识图谱导出功能完成 issue 1. 继续完成文本保存的工作 issue ...

  6. UVA-1498 Activation

    UVA-1498 DP应该是肯定的,设 f [ i ] [ j ] 表示现在对中共有 i 人,Tomato在第 j 个,出现所求情况的概率,我们可以很(简单的)艰难的列出下列方程: f[i][1] = ...

  7. systemverilog 字符串类型

    转载:https://blog.csdn.net/Holden_Liu/article/details/100727957 传统的Veriog仅仅支持文字表述上的字符串, 而SystemVerilog ...

  8. Jquery取值方法汇总

    一.下拉框 1.jquery获取当前选中select的text值 var a = $("#ShareMoneyType").find("option:selected&q ...

  9. nod_1009 数字1的数量(分析题)

    题意: 给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的个数. 例如:n = 12,包含了5个1.1,10,12共包含3个1,11包含2个1,总共5个1. Input 输入 ...

  10. hdu 3887 Counting Offspring(DFS序【非递归】+树状数组)

    题意: N个点形成一棵树.给出根结点P还有树结构的信息. 输出每个点的F[i].F[i]:以i为根的所有子结点中编号比i小的数的个数. 0<n<=10^5 思路: 方法一:直接DFS,进入 ...