当前位置: 首页 > news >正文

Luogu P10778 BZOJ3569 DZY Loves Chinese II 题解 [ 紫 ] [ Xor Hashing ] [ 线性基 ] [ DFS 树 ]

DZY Loves Chinese II

一道喵喵哈希题。

对于连通性问题,可以考虑对原图建出 DFS 树,然后对于不同的边采取不同的处理方式。在本题中,如果需要把原图割开,那么至少需要存在一条树边,使得经过它的非树边全都被割开,且它自己被割开

于是问题被转化为了判断给定边集是否为原图上部分特定边集的超集。

直接做显然是不好做的。我们考虑 Xor Hashing,为每条边随机赋权,然后记录下这 \(n - 1\) 个特殊边集所有边的异或和。对于给定边集的一次询问,我们需要判断是否存在一个子集的异或和与某个特殊边集的异或和相同,这个显然是可以线性基判断的。因为必须枚举每个特殊边集,所以此时时间复杂度为 \(O(qn\log V)\),无法通过。

考虑这个做法瓶颈在于哪里。显然是因为我们每个特殊边集的异或和是不同的,但是我们无需判断到底是哪个特殊边集与之匹配,而是只要存在一个与之匹配即可。于是我们考虑把所有特殊边集的异或和全部赋为同一个值:\(\bm 0\)。现在的问题就是该如何构造出这样的边权分配方案。

依然是从 DFS 树的角度考虑,分类讨论不同的边:

  • 树边:用于控制最后的异或和为 \(0\)。一开始我们不给它赋值,待到其他边全部随机赋权完了以后,再来给他赋值以满足构造要求。
  • 返祖边:随机赋权,并且对 DFS 树上的返祖链进行覆盖,全部异或上自己的权值。可以用树上差分实现。
  • 前向边:不管它,因为他在作为返祖边的时候已经赋值一遍了。
  • 横叉边:无向图没有横叉边。

容易证明,所有跨过树边 \(e\) 的返祖边都恰好覆盖了 \(e\) 一次,因此 \(e\) 的权值取最后异或和的值即可。

接下来只要判断给定边集是否存在一个异或和为 \(0\) 的非空子集即可。我们把给定边集的权值插入线性基中,如果存在一个数插入失败,则证明存在一个异或和为 \(0\) 的非空子集;否则这个线性基的秩等于插入元素个数,说明不存在满足要求的非空子集。

时间复杂度 \(O(n + m+ qk\log V)\)。正确率就是 Xor Hashing 的正确率。注意构造的时候可以参考 Tarjan 求 EDCC 的写法,可以比较容易地判重边。

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 100005, M = 1000005;
const ll MXV = 1000000000000000000ll;
mt19937_64 rnd((unsigned) time(NULL));
ll rd(ll l, ll r)
{return uniform_int_distribution<ll> (l, r) (rnd);
}
int n, m, q, h[N], eidx = 1;
struct Edge{int v, ne;ll w;
} e[M];
void add(int u, int v)
{e[++eidx] = {v, h[u]};h[u] = eidx;
}
int dcnt = 0, dfn[N], tot;
ll ew[N];
bitset<N> vis;
void dfs(int u, int ineg)
{dfn[u] = ++tot;vis[u] = 1;dcnt++;for(int i = h[u]; i ; i = e[i].ne){int v = e[i].v;if((i ^ 1) == ineg) continue;if(vis[v]){if(dfn[v] > dfn[u]) continue;e[i].w = e[i ^ 1].w = rd(1, MXV);ew[u] ^= e[i].w;ew[v] ^= e[i].w;continue;}dfs(v, i);ew[u] ^= ew[v];}e[ineg].w = e[ineg ^ 1].w = ew[u];
}
struct Linear_Base{ll p[70];void init(){memset(p, 0, sizeof(p));}bool insert(ll x){for(int i = 63; i >= 0; i--){if((x >> i) & 1){if(p[i]) x ^= p[i];else{p[i] = x;return 1;}}}return 0;}
} lnb;
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> m;for(int i = 1; i <= m; i++){int u, v;cin >> u >> v;add(u, v);add(v, u);}    dfs(1, 0);cin >> q;int lastans = 0;while(q--){if(dcnt != n){cout << "Disconnected\n";continue;}int k;cin >> k;lnb.init();bool res = 1;while(k--){int id;cin >> id;id ^= lastans;res &= lnb.insert(e[2 * id].w);}lastans += res;if(res == 0) cout << "Disconnected\n";else cout << "Connected\n";}return 0;
}
http://www.jsqmd.com/news/47020/

相关文章:

  • CSS基础语法 - 指南
  • MineContext:我第一次感觉 AI 真正在“主动帮我管理生活”
  • NCHU OOP-BLOG1-电梯调度-23207329-姚子康 - 翊尘
  • 操作系统的基本概念
  • 「Temp」目录
  • Linksys HTTPd缓冲区溢出远程代码执行漏洞深度解析
  • .NET+AI | MEAI | Function Calling 基础(3)
  • 开发智联笔记项目时所遇问题(8)
  • 高中学习机五大品牌终极横评:优缺点一览,找到最适合你的那一款!
  • NCHU-23207335-面向对象程序设计-BLOG-1
  • 开发智联笔记项目时所遇问题(4)
  • 开发智联笔记项目时所遇问题(3)
  • 20251121周五日记
  • 卡码网94: bellman_ford算法
  • CrewAI 上手攻略:多 Agent 自动化处理复杂任务,让 AI 像员工一样分工协作
  • 题解:AT_agc067_d [AGC067D] Unique Matching
  • 开发智联笔记项目所遇问题
  • 计算机视觉——从环境配置到跨线计数的完整实现基于 YOLOv12 与质心追踪器的实时人员监控优秀的系统
  • 搜维尔科技:利用MANUS数据手套实现灵巧远程操作:对20自由度灵巧手进行控制
  • 2025-11-21 早报新闻
  • CTF reverse入门记录
  • 开发智联笔记项目时的js问题
  • nju实验一选择器
  • 上海金蝶代理商推荐——上海宝蝶信息技术有限公司
  • 11.21模拟赛
  • HTML---------------图片转换(草稿)
  • 爱与时间反应鲜红色慢慢退却 一次次重复直到忘记了誓言
  • Mac 安装 JDK 8u281(JDK-8u281-1.dmg)详细步骤(附安装包)
  • chrome: 允许远程调试
  • Agent skills 实战