2020-2021 Winter Petrozavodsk Camp, Day 9 Contest (XXI Open Cup, Grand Prix of Suwon) F. Find the XOR
题意: 给一个n个点m条带权边的连通图(有环有自环有重边),定义 d ( u , v ) d(u,v) d(u,v)为u到v的一条路径中每条边xor的和的最大值,给q次询问,每次询问一个 l , r l, r l,r,求所有 l ≤ i < j ≤ r l \leq i < j \leq r l≤i<j≤r 的 d ( i , j ) d(i,j) d(i,j) 的最大值
思路://
1.从u到v的每一条路径上的边异或和 都可以用 u到v的任意一条路径 和 图中若干环 的异或和 表示
2.u到v的任意一条路径的异或和可以用从根到u的路径(P(root, u) )异或上从根到v的路径得到,表示为 P ( u , v ) = P ( r o o t , u ) ⨁ P ( r o o t , v ) P(u, v) = P(root, u) \bigoplus P(root, v) P(u,v)=P(root,u)⨁P(root,v)
3.L到R区间内的所有 d ( i , j ) d(i,j) d(i,j)的异或和可以表示为 P ( r o o t , i ) ⨁ P ( r o o t , j ) P(root, i) \bigoplus P(root, j) P(root,i)⨁P(root,j) 的异或和,根据异或的性质,为0或从P(root, L) 异或到 P(root, R) 的区间异或和
4.设mx(x)为x与线性基异或的最大值
mn(x)为x与线性基异或的最小值
m x ( x 1 ) ⨁ m x ( x 2 ) = m n ( x 1 ⨁ x 2 ) mx(x1)\bigoplus mx(x2)=mn(x1\bigoplus x2) mx(x1)⨁mx(x2)=mn(x1⨁x2)
m x ( x 1 ) ⨁ m x ( x 2 ) ⨁ m x ( x 3 ) = m x ( x 1 ⨁ x 2 ⨁ x 3 ) mx(x1)\bigoplus mx(x2)\bigoplus mx(x3)=mx(x1\bigoplus x2\bigoplus x3) mx(x1)⨁mx(x2)⨁mx(x3)=mx(x1⨁x2⨁x3)
5.线性基可以将很大的一个数的集合等价成 最高有效二进制位 个数的集合,并且两个集合中取若干个数能生成的异或和的集合是相同的,线性基从高位向低位枚举可以做到取一个数和这个集合的异或的最大或最小
6.环可以由dfs序得到
有空自己补下代码(… 挖坑
这道题我真的没忍住想发发,顺便狂%队友
队友的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1 << 17;
const int maxbit = 30;
struct L_B {
int lba[maxbit];
bool empty;
L_B() {
memset(lba, 0, sizeof(lba));
empty = 1;
}
void insert(int val) {
empty = 0;
for (int i = maxbit - 1; i >= 0; --i)
if (val & (1 << i)) {
//
if (!lba[i]) {
lba[i] = val;
break;
}
val ^= lba[i];
}
}
int query1(int ans) {
for (int i = maxbit - 1; i >= 0; i--) {
if (ans < (ans ^ lba[i])) ans ^= lba[i];
}
return ans;
}
int query2(int ans) {
for (int i = maxbit - 1; i >= 0; i--) {
if (ans > (ans ^ lba[i])) ans ^= lba[i];
}
return ans;
}
} base;
struct edge {
int to, v;
int num;
};
int dfn[N], dfs_clock;
vector<edge> g[N];
int val[N];
void tarjan(int u, int fa) {
dfn[u] = ++dfs_clock;
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i].to;
if (!dfn[v]) {
val[v] = g[u][i].v ^ val[u];
tarjan(v, g[u][i].num);
} else if (g[u][i].num != fa) {
base.insert(val[v] ^ val[u] ^ g[u][i].v);
}
}
}
int xr[N];
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int n, m, q;
cin >> n >> m >> q;
for (int i = 1; i <= m; i++) {
int a, b, c;
cin >> a >> b >> c;
g[a].push_back({
b, c, i});
g[b].push_back({
a, c, i});
}
tarjan(1, 0);
for (int i = 1; i <= n; i++) xr[i] = xr[i - 1] ^ val[i];
while (q--) {
ll a, b;
cin >> a >> b;
ll x = xr[b] ^ xr[a - 1];
if ((b - a + 1) % 2 == 1) x = 0;
if ((b - a + 1) * (b - a) / 2 % 2 == 1) {
cout << base.query1(x) << endl;
} else {
cout << base.query2(x) << endl;
}
}
}