【BZOJ-4184 】 Shallot 線段樹按時間分治 + 線性基

4184: shallot

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 356  Solved: 180
[Submit][Status][Discuss]

Description

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

每一個時刻她會給小蔥一顆小蔥苗或者是從小蔥手裏拿走一顆小蔥苗,而且讓小蔥從本身手中的小蔥苗裏選出一些小蔥苗使得選出的小蔥苗上的數字的異或和最大。
這種小問題對於小蔥來講固然不在話下,可是他的身邊沒有電腦,因而他打電話給同爲Oi選手的你,你能幫幫他嗎?
你只須要輸出最大的異或和便可,若小蔥手中沒有小蔥苗則輸出0。

Input

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

Output

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

Sample Input

6
1 2 3 4 -2 -3

Sample Output

1
3
3
7
7
5

HINT

 N<=500000,Ai<=2^31-1spa

Source

Solution

新姿式,線段樹對時間分治。
詢問能夠直接利用線性基貪心求解,問題在於線性基不支持刪除操做。blog

考慮對時間分治,就是按時間建線段樹,對於一個數,獲得他的存在時間區間$[l,r]$,而後對線段樹上相應節點記錄這個數。遊戲

最後DFS線段樹,在葉子節點求解。ip

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
*/
相關文章
相關標籤/搜索