【BZOJ-4184 】 Shallot 线段树按时间分治 + 线性基

4184: shallot

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

1
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
*/

  

posted @ 2017-03-24 18:42  DaD3zZ  阅读(898)  评论(1编辑  收藏