【bzoj4184】 shallot 线段树对时间分治+线性基

有这样一类问题,插入、删除、整体查询。

为了避免删除操作,一般记录每个点的进入时间和删除时间,在线段树里每个节点开一个vector,然后这个区间里插入这个数,最后dfs一遍就只有插入操作,没有删除操作了。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#define maxn 500010

using namespace std;

struct yts
{
	int l,r;
	vector<int> d;
}t[4*maxn];

struct yts1
{
	int a[31];
	int& operator[](int x)
	{
		return a[x];
	}
}c;

int n,m;
int a[maxn];
set<pair<int,int> > p;

yts1 insert(yts1 c,int x)
{
	for (int i=30;i>=0;i--)
	  if ((x>>i)&1)
	  {
	  	if (!c[i])
	  	{
	  		c[i]=x;
	  		break;
	  	}
	  	else x^=c[i];
	  }
	return c;
}

void build(int i,int l,int r)
{
	t[i].l=l;t[i].r=r;
	if (l==r) return;
	int mid=(l+r)/2;
	build(i*2,l,mid);build(i*2+1,mid+1,r);
}

void insert(int i,int l,int r,int x)
{
	if (l<=t[i].l && t[i].r<=r)
	{
		t[i].d.push_back(x);
		return;
	}
	int mid=(t[i].l+t[i].r)/2;
	if (l<=mid) insert(i*2,l,r,x);
	if (mid<r) insert(i*2+1,l,r,x);
}

void dfs(int i,yts1 k)
{
	for (int j=0;j<t[i].d.size();j++)
	  k=insert(k,t[i].d[j]);
	if (t[i].l==t[i].r)
	{
		int now=0;
		for (int i=30;i>=0;i--)
		  if ((now^k[i])>now) now^=k[i];
		printf("%d\n",now);
		return;
	}
	dfs(i*2,k);
	dfs(i*2+1,k);
}

int main()
{
	scanf("%d",&n);
	build(1,1,n);
	for (int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		if (x>0) p.insert(make_pair(x,i));
		else
		{
			pair<int,int> q=*p.lower_bound(make_pair(abs(x),0));
			insert(1,q.second,i-1,abs(x));
			p.erase(q);
		}
	}
	set<pair<int,int> >::iterator i;
	for (i=p.begin();i!=p.end();i++) insert(1,(*i).second,n,(*i).first);
	dfs(1,c);
	return 0;
}


你可能感兴趣的:(【bzoj4184】 shallot 线段树对时间分治+线性基)