线性基 + 并查集
给一个1-base数组{a},有N次操作,每次操作会使一个位置无效。一个区间的权值定义为这个区间里选出一些数的异或和的最大值。求在每次操作前,所有不包含无效位置的区间的权值的最大值。
输入描述:
第一行读入一个正整数(1 <= n <= 105)
第二行读入n个正整数,第i个表示a[i](0<= a[i] <= 109)
第三行读入n个正整数,第i个表示x[i]即第i次操作的位置,保证x[i]互不相同。
输出描述:
输出n行答案
示例1
输入
10 169 816 709 896 58 490 97 254 99 796 4 2 3 10 5 6 1 8 9 7
输出
1023 994 994 994 490 490 254 254 99 97
题意 : 每次让一个位置得数失效,求解连续区间上异或值最大得是多少?
思路分析 : 每次让一个位置失效,那么这个问题就可以逆向去考虑,每次加一个数,这个总比删除操作好处理,用并查集就可以,然后就是一个在套一个线性基就可以
代码示例 :
#define ll long long const int maxn = 1e5+5; const int mod = 1e9+7; const double eps = 1e-9; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; int n; int pre[maxn], pos[maxn]; int f[maxn]; int val[maxn][40]; int an[maxn]; int fid(int x){ if (x != f[x]) f[x] = fid(f[x]); return f[x]; } void insert(int b[], int x){ for(int i = 30; i >= 0; i--){ if (x>>i&1){ if (!b[i]) {b[i] = x; break;} else x ^= b[i]; } } } void unit(int p1, int p2){ int x = fid(p1), y = fid(p2); for(int i = 0; i <= 30; i++){ if (val[y][i]) insert(val[x], val[y][i]); } f[y] = x; } int solve(int p){ int ans = 0; for(int i = 30; i >= 0; i--){ if ((ans^val[p][i]) > ans) { ans ^= val[p][i]; } } return ans; } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); cin >> n; for(int i = 1; i <= n; i++) scanf("%d", &pre[i]); for(int i = 1; i <= n; i++) scanf("%d", &pos[i]); memset(f, 0, sizeof(f)); int ans = 0; for(int i = n; i >= 1; i--){ int x = pos[i]; // 位置 f[x] = x; insert(val[x], pre[x]); if (f[x-1]) unit(x, x-1); if (f[x+1]) unit(x, x+1); ans = max(ans, solve(x)); an[i] = ans; } for(int i = 1; i <= n; i++) printf("%d\n", an[i]); return 0; }
东北日出西边雨 道是无情却有情