CF1893E. Cacti Symphony

最近见过的最简单的一道 3500。

题目链接:E - Cacti Symphony

题目大意:给定无向连通图,满足其任意一个点至多存在在一个简单环中,给出的每条边都会扩张成一条长度 \(\le 10^9\) 的链。要求对每个点和边染 \([1,3]\) 内的颜色,使得:对于每条边,其连接的两点的权值的异或和不等于 \(0\),也不等于该边的边权;对于每个点,与其相连的所有边的权值的异或和不等于 \(0\),也不等于该点的点权。求合法染色方案数,对 \(998244353\) 取模。\(n\le 5\times 10^5,m\le 10^6\)

首先分析边相关的性质,根据题意可以得出:

  • \(col_u\neq col_v\)
  • \(col_u\oplus col_v \neq col_e\)

注意到由于 \(col_i\in [1,3]\),所以 \(col_u\oplus col_v \neq col_u,col_v\)。又由 \(col_u\neq col_v\) 可以推出 \(col_u\oplus col_v\in [1,3]\),最终得出 \(col_e=col_u\)\(col_v\)。也就是说,每条边的颜色必然会属于两端点中的一个。这里若 \(col_e=col_u\) 我们就认为边是 \(u\to v\) 的,然后观察点的性质。

\(deg_i\) 表示 \(i\) 的度数,\(out_i\) 表示 \(i\) 的出度,来分析点合法的条件:

  • 对任意与 \(i\) 有边相连的点 \(j\),必然有 \(col_j\neq col_i\),这是之前就分析过的
  • 观察与 \(i\) 相连的所有边权,这些边权有 \(out_i\) 个就是 \(col_i\),其余的都是 \(col_j\)
  • 关于异或和的限制,异或结果只会在 \([0,3]\) 内,不能是 \(col_i\)\(0\),那就必须是某个 \(col_j\)
  • 注意到 \(1\oplus 2\oplus 3=0\),所以若 \(in_i\) 为偶数则 \(col_j\) 两两配对异或后必然是 \(col_i\)\(0\),导致非法,所以得出 \(in_i\) 必须为奇数

于是分析过后,题目中的限制就被完成转化成了:

  • 给每个点染色,要求任意有边相连的两点颜色不能相同
  • 给每条边定向,要求任意点的入度必须为奇数

发现两个问题分别独立,可以分开求解。

染色部分,对于单个环而言其实是一个经典问题,考虑某点两侧颜色是否相同可以得到 \(f_n=f_{n-1}+2f_{n-2}\)。那么发挥惊人注意力即可得出 \(f_n=2^n+2\times (-1)^n\)

考虑割边带来的贡献,我们把单个点也看成一个方案数为 \(3\) 的环,那么可以发现每连一条割边就相当于把方案数乘上 \(\frac{2}{3}\),那么统计割边数目即可。

定向部分,相当于对每条边而言,可以选一个点反色,目标是让所有点都变成另一种颜色。这个问题如果放在树上是个很经典的问题,从叶子向上贪即可。所以考虑随便求出一个生成树,对于非树边可以随便定向,最后再生成树上调整即可。调整方案若存在则必唯一。

合法性也容易判断,\(m\) 条边 \(m\) 个入度,所以 \(n,m\) 奇偶性必须相同。对应方案数就是 \(2^{m-n+1}\),最后把两边的答案乘起来就是最终的结果。

实现方面,对于求环长其实没必要跑 tarjan,充分利用无向图搜索树的性质记录每个点的深度以及访问情况即可。

#include<bits/stdc++.h>
using namespace std;
#define N 500050
#define LL long long
#define MOD 998244353
int n,mm;
LL tot,m,dep[N],ans;
vector<pair<int,int>>d[N];
LL qow(LL x,LL y){return y?(y&1?x*qow(x,y-1)%MOD:qow(x*x%MOD,y/2)):1;}
LL F(LL n){return (qow(2,n)+(n&1?MOD-2:2))%MOD;}
void dfs(int x,int pre)
{
	for(auto pi:d[x]){
		int y=pi.first,w=pi.second;
		if(y==pre)continue;
		if(dep[y]){
			if(dep[y]<dep[x]){
				(ans*=F(dep[x]-dep[y]+w))%=MOD;
				tot-=dep[x]-dep[y]+w;
				m-=dep[x]-dep[y]+w;
			}
			continue;
		}
		dep[y]=dep[x]+w;
		dfs(y,x);
	}
}
int main()
{
	scanf("%d%d",&n,&mm);
	while(mm--){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		d[x].push_back(make_pair(y,z+1));
		d[y].push_back(make_pair(x,z+1));
		m+=z+1;
		tot+=z;
	}
	tot+=n;ans=qow(2,m-tot+1);
	if((tot^m)&1)return printf("0\n"),0;
	dep[1]=1,dfs(1,0);
	printf("%lld\n",ans*qow(3,tot)%MOD*qow((2*MOD+2)/3,m)%MOD);
}
posted @ 2026-07-31 19:01  DeaphetS  阅读(3)  评论(0)    收藏  举报