[BZOJ4184]shallot

一、題目

小苗去市場上買了一捆小蔥苗,她突然一時興起,於是她在每顆小蔥苗上寫上一個數字,然後把小蔥叫過來玩遊戲。

每個時刻她會給小蔥一顆小蔥苗或者是從小蔥手裏拿走一顆小蔥苗,並且讓小蔥從自己手中的小蔥苗裏選出一些小蔥苗使得選出的小蔥苗上的數字的異或和最大。

這種小問題對於小蔥來說當然不在話下,但是他的身邊沒有電腦,於是他打電話給同爲Oi選手的你,你能幫幫他嗎?

你只需要輸出最大的異或和即可,若小蔥手中沒有小蔥苗則輸出0。

Input
第一行一個正整數n表示總時間;第二行n個整數a1,a2…an,若ai大於0代表給了小蔥一顆數字爲ai的小蔥苗,否則代表從小蔥手中拿走一顆數字爲-ai的小蔥苗。

Output
輸出共n行,每行一個整數代表第i個時刻的最大異或和。

Note
N500000,Ai2311N\leq 500000,A_i\leq 2^{31}-1

二、解法

線性基是很難刪除的,可以用線段樹分治,我們求出每一個值覆蓋的時間範圍,把它打到線段樹上,然後再跑一邊線段樹,這樣就只需要修改了,帶着線性基讓下傳,在l=rl=r時就詢問。

至於求出一個覆蓋的時間範圍,我用的是mapmapvectorvector,詳細請康代碼。

#include <cstdio>
#include <vector>
#include <cstring>
#include <map>
using namespace std;
const int M = 500005;
int read()
{	
	int x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*flag;
}
int n,m,sz,L[M],R[M],val[M];vector<int> t[4*M];
map<int,vector<int> > mp;
struct basis
{
	int p[40];
	basis() {memset(p,0,sizeof p);}
	void ins(int x)
	{
		for(int i=30;i>=0;i--)
		{
			if(!(x>>i&1)) continue;
			if(!p[i]) {p[i]=x;return;}
			x^=p[i];
		}
	}
	int ask()
	{
		int t=0;
		for(int i=30;i>=0;i--)
			if((t^p[i])>t) t^=p[i];
		return t;
	}
};
void ins(int i,int l,int r,int L,int R,int v)
{
	if(L>r || l>R) return ;
	if(L<=l && r<=R)
	{
		t[i].push_back(v);
		return ;
	}
	int mid=(l+r)>>1;
	ins(i<<1,l,mid,L,R,v);
	ins(i<<1|1,mid+1,r,L,R,v);
}
void ask(int i,int l,int r,basis a)
{
	for(int j=0;j<t[i].size();j++)
		a.ins(t[i][j]);
	if(l==r)
	{
		printf("%d\n",a.ask());
		return ;
	}
	int mid=(l+r)>>1;
	ask(i<<1,l,mid,a);
	ask(i<<1|1,mid+1,r,a);
}
signed main()
{
	n=read();
	for(int i=1;i<=n;i++)
	{
		int x=read();
		if(x>0)
		{
			mp[x].push_back(++m);
			L[m]=i;val[m]=x;
		}
		else
		{
			x=-x;sz=mp[x].size()-1;
			R[mp[x][sz]]=i-1;
			mp[x].pop_back();
		}
	}
	for(int i=1;i<=m;i++)
	{
		if(!R[i]) R[i]=n;
		ins(1,1,n,L[i],R[i],val[i]);
	}
	basis fuck;
	ask(1,1,n,fuck);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章