洛谷 P5607 [Ynoi2013] 无力回天 NOI2017
人生第一道Ynoi,开心
Description
https://www.luogu.com.cn/problem/P5607
Solution
拿到这个题,看了一下,发现询问要求最大异或和,怎么办?
没办法,我只学过线性基,就顺着这个思路硬上吧。
我们开一颗线段树,里面的节点存线性基,那么空间复杂度是的
先不管修改操作,那么我们容易分析得到单次查询的复杂度是
这个复杂度一看就是正解,接着想修改
区间还得维护线性基???什么鬼???
我们想,区间在线段树上难以办到,但是单点很简单
怎么办?
差分啊!!!
但我们怎么差分才能保证正确性呢?
熟知,对于一个数列
如果我们把它差分,使得
那么由线性代数基础知识,数列的线性基和原数列的线性基是一样的
这启发我们线段树维护差分的线性基,然后再单独维护,询问时将插入线段树查询得到的线性基、
这个就很好维护了,直接上线段树或者树状数组维护差分即可
这样,单次修改复杂度为
Code
#include <cstdio> #include <iostream> using namespace std; const int N = 50010; int n, m, a[N], b[N], opt, l, r, v; inline int read() { int res = 0, flag = 0; char ch = getchar(); for(; !isdigit(ch); ch = getchar()) if(ch == '-') flag = 1; for(; isdigit(ch); ch = getchar()) res = (res << 1) + (res << 3) + (ch ^ 48); if(flag) res = ~res + 1; return res; } struct LineBase{ int a[31]; inline void clear() {for(int i = 0; i < 31; ++i) a[i] = 0;} inline void insert(int x) { for(int i = 30; i + 1; --i) if(x & (1 << i)) if(!a[i]) {a[i] = x; break;} else x ^= a[i]; } }O; inline LineBase merge(LineBase x, LineBase y) { for(int i = 30; i + 1; --i) if(y.a[i]) x.insert(y.a[i]); return x; } struct SegmentTree{ #define lc (k << 1) #define rc (lc | 1) #define mid (l + r >> 1) LineBase tr[N << 2]; inline void update(int k) {tr[k] = merge(tr[lc], tr[rc]);} inline void build(int k, int l, int r) { if(l == r) {tr[k].insert(b[l]); return;} build(lc, l, mid), build(rc, mid + 1, r), update(k); } inline void modify(int k, int l, int r, int loc) { if(l > loc || r < loc) return ; if(l == r) {tr[k].clear(), tr[k].insert(b[l]); return;} modify(lc, l, mid, loc), modify(rc, mid + 1, r, loc), update(k); } inline LineBase query(int k, int l, int r, int L, int R) { if(l > R || r < L) return O; if(L <= l && r <= R) return tr[k]; return merge(query(lc, l, mid, L, R), query(rc, mid + 1, r, L, R)); } }s; struct BIT{ #define lowbit(x) (x & -x) int tr[N]; inline void insert(int x, int v) {for(; x <= n; x += lowbit(x)) tr[x] ^= v;} inline int query(int x) {int res = 0; for(; x; x -= lowbit(x)) res = res ^ tr[x]; return res;} }bit; inline void out(int x) { int flag = 0; for(int i = 30; i + 1; --i) if(flag) printf("%d",((x & (1 << i)) > 0)); else if(x & (1 << i)) printf("1"), flag = 1; if(!flag) printf("0"); } int main() { n = read(), m = read(); for(int i = 1; i <= n; ++i) a[i] = read(), b[i] = a[i] ^ a[i - 1], bit.insert(i, b[i]); b[n + 1] = a[n]; s.build(1, 1, n + 1); for(int i = 1; i <= m; ++i) { opt = read(), l = read(), r = read(), v = read(); if(opt == 1) { b[l] ^= v, b[r + 1] ^= v; bit.insert(l, v), bit.insert(r + 1, v); s.modify(1, 1, n + 1, l), s.modify(1, 1, n + 1, r + 1); } else { LineBase ans = s.query(1, 1, n + 1, l + 1, r); ans.insert(bit.query(l)); for(int j = 30; j + 1; --j) if((ans.a[j] ^ v) > v) v ^= ans.a[j]; printf("%d\n",v); } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通