【BZOJ4184】shallot 线段树+vector+线性基

【BZOJ4184】shallot

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

题解:因为线性基不支持删除操作,所以我们要考虑离线的做法

有一个性质很重要:每个数都存在于一段连续的区间,所以我们可以用map来记录区间的起始位置和结束位置,然后用线段树来实现区间操作。

具体方法是给线段树上的每一个节点都开一个vector,vector里维护的就是线性基,每次更新到一整块区间就在线性基中加入这个数,并维护线性基。查询的时候我们将每个点到根的路径上的所有的线性基再开一个vector扔进去,并维护线性基,然后贪心求出最大值就行了。

一开始感觉空间复杂度有点吓人,不过当我TLE时才发现其实内存完全不虚。

然后发现,算法的瓶颈其实在于查询操作,所以我们不能每次都进行单点查询,而是遍历整棵线段树,并输出所有的答案。

拍极限数据的时候我跑了6、7秒感觉GG,但是测了一下标程才发现标程比我的还慢,所以果断AC。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <map>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=500010;
int n,m;
int last[maxn],A[maxn];
map<int,int> mp;
struct line
{
	vector<int> v;
	int gauss(int x)
	{
		int i;
		for(i=0;i<v.size();i++)	if((x^v[i])<x)	x^=v[i];
		if(x)
		{
			v.push_back(x);
			for(i=v.size()-1;i;i--)	if(v[i]>v[i-1])	swap(v[i],v[i-1]);
		}
		return x;
	}
	int getmax()
	{
		int i,ret=0;
		for(i=0;i<v.size();i++)	if((ret^v[i])>ret)	ret^=v[i];
		return ret;
	}
};
line s[maxn<<2],emp;
void updata(int l,int r,int x,int a,int b,int c)
{
	if(a<=l&&r<=b)
	{
		s[x].gauss(c);
		return ;
	}
	int mid=l+r>>1;
	if(a<=mid)	updata(l,mid,lson,a,b,c);
	if(b>mid)	updata(mid+1,r,rson,a,b,c);
}
void query(int l,int r,int x,line q)
{
	for(int i=0;i<s[x].v.size();i++)	q.gauss(s[x].v[i]);
	if(l==r)
	{
		printf("%d
",q.getmax());
		return ;
	}
	int mid=l+r>>1;
	query(l,mid,lson,q),query(mid+1,r,rson,q);
}
int main()
{
	scanf("%d",&m);
	int i,a;
	for(i=1;i<=m;i++)
	{
		scanf("%d",&A[i]);
		if(A[i]<0)	a=mp[-A[i]],last[a]=i-1;
		else	mp[A[i]]=i;
	}
	for(i=1;i<=m;i++)
	{
		if(A[i]<0)	continue;
		if(!last[i])	last[i]=m;
		updata(1,m,1,i,last[i],A[i]);
	}
	query(1,m,1,emp);
	return 0;
}
原文地址:https://www.cnblogs.com/CQzhangyu/p/7054379.html