#define mset(a) memset(a,0,sizeof(a)) constint FOUND = 1, VISITED = 2, UNFOUND = 3; //找到了,重复找,未找到 structTrie { int index = 0; //用以做编号 structNode { int qcnt = 0, exist = 0, etc; //字符串访问次数,是否为字符串等附加信息 int son[50] = {}; //儿子节点 //字符串这里意为完整的、自根节点到叶子节点组成的字符串 } node[500000 + 10];
intgetid(char ch){ return ch - 'a'; }
voidinsert(char s[])//插入操作 { int sons, root = 0, len = strlen(s); for (int i = 0; i <= len - 1; i++) { sons = getid(s[i]); if (!node[root].son[sons]) node[root].son[sons] = ++index; root = node[root].son[sons]; } node[root].exist = 1; //标记这是个字符串 }
intfind(char s[])//查询操作 { int sons, root = 0, len = strlen(s); for (int i = 0; i <= len - 1; i++) { sons = getid(s[i]); if (!node[root].son[sons]) return UNFOUND; root = node[root].son[sons]; } if (!node[root].exist) return UNFOUND; if (!node[root].qcnt) { node[root].qcnt++; return FOUND; } return VISITED; } } trie;
voiddsu(ll root, ll dad, ll keep){ for (auto son: e[root]) { if (son == dad || son == big[root]) continue; dsu(son, root, 0); } if (big[root]) dsu(big[root], root, 1); for (auto son: e[root]) { if (son == dad || son == big[root]) continue; for (ll i = L[son]; i <= R[son]; i++) { ans += cnt[d[dfn[i]]] * (d[dfn[i]] - d[root]); } for (ll i = L[son]; i <= R[son]; i++) { cnt[d[dfn[i]]]++; } } cnt[d[root]]++; if (keep == 0) { for (ll i = L[root]; i <= R[root]; i++) { cnt[d[dfn[i]]]--; } } }
也就是说,到点 x 的简单路径上最大边权的最小值 \(\leq val\) 的所有点 y 均在 Kruskal
重构树上的某一棵子树内,且恰好为该子树的所有叶子节点。
注意重构树新建了节点,初始化范围为 \(n+m\)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
sort(h + 1, h + 1 + m, cmp);//按照边权排序 for (ll i = 1; i <= m; i++) { ll u = s.find(h[i].u), v = s.find(h[i].v);//并查集 if (u != v) { cnt++; s.merge(u, cnt); s.merge(v, cnt); high[cnt] = h[i].len;//点权为边权 e[u].push_back(cnt); e[cnt].push_back(u); e[v].push_back(cnt); e[cnt].push_back(v); } } dfs(cnt, cnt);
const ll N = 1e5 + 10, M = 52; ll n, p[M + 10], d[M + 10], dcnt;
voidinsert(ll x){ for (ll i = M; i >= 0; i--) { if ((x >> i) & 1ll) { if (!p[i]) { p[i] = x; return; } x ^= p[i]; } } // 运行到这里说明可以表示 0 }
ll queryMax(ll ret = 0){ for (ll i = M; i >= 0; i--) { ret = max(ret, ret ^ p[i]); } return ret; }
//最小值就是线性基最小的元素
voidrebuild(){ // 重建为行简化,其中 d[] 去除 0 位,必须在排名相关操作前进行一次 dcnt = 0; for (ll i = M; i >= 0; i--) for (ll j = i - 1; j >= 0; j--) if (p[i] & (1ll << j)) { p[i] ^= p[j]; } for (ll i = 0; i <= M; i++) if (p[i]) { d[dcnt++] = p[i]; } }
ll kthMin(int k){ if (k >= (1ll << dcnt)) { return-1; } ll ans = 0; for (ll i = M; i >= 0; i--) if (k & (1ll << i)) { ans ^= d[i]; } return ans; }
ll rankMin(ll x){ ll ans = 0; for (ll i = dcnt - 1; i >= 0; i--) if (x >= d[i]) ans += (1 << i), x ^= d[i]; return ans; }
voidsolve(){ cin >> n; for (ll i = 1, a; i <= n; i++) { cin >> a; insert(a); } cout << queryMax() << endl; }
ull deg(ull num, int deg){ return num & (1ull << deg); }
cin >> n; for (int i = 1; i <= n; ++i) cin >> a[i]; int row = 1; for (int col = 52; ~col && row <= n; --col) { for (int i = row; i <= n; ++i) { if (deg(a[i], col)) { swap(a[row], a[i]); break; } } if (!deg(a[row], col)) continue; for (int i = 1; i <= n; ++i) { if (i == row) continue; if (deg(a[i], col)) { a[i] ^= a[row]; } } ++row; }