这个SB题才 2000?
是我对2000分rating 有什么误解吗?这玩意还要ECC来写
思路:
就是缩点,判环,奇环环长必须全部都是0,否则就是权值必须全部相等,偶数环,只有全部缺失值才会有 V 的贡献
要不是有ECC板子才不会尝试这题*
判断奇数环和值,dfs染色判断奇数环,并在过程中记录一个变量 val 判断就完了
代码:
`
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define all(v) v.begin(), v.end()
#define pb push_back
#define inf32 INT_MAX
#define inf64 LLONG_MAX
// #define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int,int> pii;
mt19937_64 rng(time(0));
ll qmi(ll a, ll k, int m){ll res=1;while(k){if(k&1)res=res*a%m;a=a*a%m;k>>=1;}return res;}
const int Maxn = 2e5 + 10, Mod = 998244353;
int n,m,k,x,y,z,q,A,B, m1, m2, l, r,u,v, V;
string s,Map[Maxn];
vector<int> cnt, num, on, vis;
vector<pii> edges;
vector<vector<pii>> G;
//邻接表,点-边编号存图,得到缩点之后的树,每个点属于哪个连通分量
ll ans;
struct ECC{
int n,cnt=0,tot=0;
vector<int> dfn,low,bel, bridge;
vector<vector<pair<int,int>>> g;
vector<vector<int>> ecc,tree;
stack<int> stk;
ECC(){}
ECC(int n,int m, vector<vector<pair<int,int>>> &G):n(n),ecc(n+5),dfn(n+5),low(n+5),bel(n+5), bridge(m+5){
g = G;
for(int i=1;i<=n;++i){
if(!dfn[i]) {
dfs(i,0);
//建超级源点
g[0].push_back({i,0});
g[i].push_back({0,0});
}
}
build();
}
//Targan dfs,栈存储边连通分量所有节点,分清树边和回边,如果dfn[id] == low[id] 这这是边连通分量的根节点
void dfs(int u,int lid){
dfn[u] = low[u] = ++ cnt;
stk.push(u);
for(auto [v,eid]: g[u]){
//树边,没遍历过,用子树更新父亲
if(!dfn[v]){
dfs(v,eid);
low[u]=min(low[u],low[v]);
if(low[v] > dfn[u]) bridge[eid] = 1;
}else if(eid != lid){ //回边,排除直接回到父节点的边
low[u] = min(low[u], dfn[v]);
}
}
//连通分量的根
if(dfn[u]==low[u]){
tot++;
while(1){
auto id = stk.top();stk.pop();
bel[id] = tot, ecc[tot].push_back(id);
if(id == u)break;
}
}
}
// 遍历原图边,若跨分量则连接一条树边,缩点建树了
void build(){
tree.resize(tot+5);
for(int u=1;u<=n;++u){
for(auto [v,e] : g[u]){
if(bel[u] != bel[v])tree[bel[u]].push_back(bel[v]);
}
}
}
};
ll work(){
ECC Ecc(n,m,G);
ll ans = 1, flg = 1;
vector<int> col(n+1,-1);
For(i,1,n){
if(col[i] != -1) continue;
// dfs 在 ECC 上染色判断奇数环还是偶数环,
// 然后判断值是否存在两个及以上
int val = -1;
auto dfs = [&](auto &&self, int u,int fa, int color) -> bool{
col[u] = color;
if(num[u] != -1){
if(val == -1){
val = num[u];
}else if(val != num[u]) flg = 0;
}
bool odd_circle = 0;
for(auto [v,eid] : G[u]){
// 桥,非同一环,回边
if(Ecc.bridge[eid] || Ecc.bel[v] != Ecc.bel[i] || eid == fa) continue;
if(col[v] == -1){ // 没涂色
odd_circle |= self(self, v, eid, color ^ 1);
}else if(col[u] == col[v]){ // 下一个点涂色了,且和当前点颜色相等,就是奇数环
odd_circle = 1;
}
}
return odd_circle;
};
if(dfs(dfs,i,0,0)){ // 奇数环,要么全部为 0, 全部值相等
if(val != -1 && val != 0) flg = 0;
}else if(val == -1){
ans = ans * V % Mod;
}
if(!flg) return 0;
}
return ans;
// return qmi(V,ans,Mod);
}
void init(){
G.resize(n+5);
For(i,1,n) G[i].clear();
num.assign(n+1,0); edges.clear();
}
void solve(){
cin >> n >> m >> V; init();
For(i,1,n) cin >> num[i];
For(i,1,m)cin >> x >> y, edges.emplace_back(x,y), G[x].pb({y,i}), G[y].pb({x,i});
cout << work() << '\n';
}
int main() {
ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
cin >> t;
while (t -- ) {
solve();
}
return 0;
}

浙公网安备 33010602011771号