【BZOJ-4184 】 Shallot 线段树按时间分治 + 线性基
4184: shallot
Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 356 Solved: 180
[Submit][Status][Discuss]
Description
小苗去市场上买了一捆小葱苗,她突然一时兴起,于是她在每颗小葱苗上写上一个数字,然后把小葱叫过来玩游戏。
每个时刻她会给小葱一颗小葱苗或者是从小葱手里拿走一颗小葱苗,并且让小葱从自己手中的小葱苗里选出一些小葱苗使得选出的小葱苗上的数字的异或和最大。
这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为Oi选手的你,你能帮帮他吗?
你只需要输出最大的异或和即可,若小葱手中没有小葱苗则输出0。
Input
第一行一个正整数n表示总时间;第二行n个整数a1,a2...an,若ai大于0代表给了小葱一颗数字为ai的小葱苗,否则代表从小葱手中拿走一颗数字为-ai的小葱苗。
Output
输出共n行,每行一个整数代表第i个时刻的最大异或和。
Sample Input
6
1 2 3 4 -2 -3
1 2 3 4 -2 -3
Sample Output
1
3
3
7
7
5
3
3
7
7
5
HINT
N<=500000,Ai<=2^31-1
Source
Solution
新姿势,线段树对时间分治。
询问可以直接利用线性基贪心求解,问题在于线性基不支持删除操作。
考虑对时间分治,就是按时间建线段树,对于一个数,得到他的存在时间区间$[l,r]$,然后对线段树上相应节点记录这个数。
最后DFS线段树,在叶子节点求解。
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 500010 int N; struct SgtNode{ int l,r; vector<int>a; }tree[MAXN<<2]; struct LNode{ int a[31]; LNode() {memset(a,0,sizeof(a));} int& operator [] (const int i) { return a[i]; } }la; inline void Insert(LNode &la,int x) { for (int i=30; i>=0; i--) { if ((x>>i)&1) { if (!la[i]) {la[i]=x; break;} else x^=la[i]; } } } map<int,int>tim; inline void Build(int now,int l,int r) { tree[now].l=l; tree[now].r=r; tree[now].a.clear(); if (l==r) return; int mid=(l+r)>>1; Build(now<<1,l,mid); Build(now<<1|1,mid+1,r); } inline void Update(int now,int L,int R,int val) { int l=tree[now].l,r=tree[now].r; if (L<=l && R>=r) { tree[now].a.push_back(val); return; } int mid=(l+r)>>1; if (L<=mid) Update(now<<1,L,R,val); if (R>mid) Update(now<<1|1,L,R,val); } inline void Query(int now,LNode LA) { int l=tree[now].l,r=tree[now].r; for (int i=0; i<tree[now].a.size(); i++) Insert(LA,tree[now].a[i]); if (l==r) { int ans=0; for (int i=30; i>=0; i--) if ((ans^LA[i])>ans) ans^=LA[i]; printf("%d\n",ans); return; } Query(now<<1,LA); Query(now<<1|1,LA); } int main() { N=read(); int st=((1LL<<31)-1); for (int i=1; i<=N; i++) { int x=read(); tim[x]=i; if (x>0) st=min(st,x); } Build(1,1,N); for (map<int,int>::iterator i=tim.find(st); i!=tim.end(); i++) { int x=i->first,tl=i->second,tr=tim[-x] ? (tim[-x]-1):N; Update(1,tl,tr,x); // printf("%d %d %d\n",x,tl,tr); } Query(1,la); return 0; } /* 6 1 2 3 4 -2 -3 */
——It's a lonely path. Don't make it any lonelier than it has to be.