4184: shallot

8 篇文章 0 订阅
7 篇文章 0 订阅

4184: shallot

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

[ Submit][ Status][ Discuss]



按线段树分治

每一个数字可以对应到线段树中的log个区间,在这些区间里面插入这个数字

对于线段树执行dfs

对于线段树每层,与上一层留下的基搞一搞再更新出新的基,然后一直往下走就行了

嗯。。。这个新增xor线性基是可以直接和上一层留下的东西操作后出来的,

不用每层再重新算。。不然常数太大了

然后那个保留基的f数组,,完全可以用深度来存,以便递归回来时及时腾出空间,不用每个节点都设一个

MLE + TLE....GG

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn = 5E5 + 50;
const int T = 8;

int n,m,cur = 1,a[maxn],b[maxn],f[40][31];

vector <int> v[maxn*T];
vector <int> p[maxn];

void Work(int o,int l,int r,int D)
{
	for (int i = 0; i < v[o].size(); i++) {
		int x = v[o][i];
		for (int j = 30; j >= 0; j--)
			if ((x>>j)&1) {
				if (!f[D][j]) {
					f[D][j] = x; 
					break;
				}
				x ^= f[D][j];
			}
	}

	if (l == r) {
		int ans = 0;
		for (int i = 30; i >= 0; i--)
			if ((ans ^ f[D][i]) > ans) ans ^= f[D][i];
		printf("%d\n",ans);
		return;
	}
	int mid = (l + r) >> 1;
	for (int i = 0; i < 31; i++) f[D+1][i] = f[D][i];
	Work(o<<1,l,mid,D+1); 
	for (int i = 0; i < 31; i++) f[D+1][i] = f[D][i];
	Work(o<<1|1,mid+1,r,D+1);
}

void Insert(int o,int l,int r,int ql,int qr,int k)
{
	if (ql <= l && r <= qr) {
		v[o].push_back(k);
		return;
	}
	int mid = (l + r) >> 1;
	if (ql <= mid) Insert(o<<1,l,mid,ql,qr,k);
	if (qr > mid) Insert(o<<1|1,mid+1,r,ql,qr,k);
}

int getint()
{
	char ch = getchar();
	int ret = 0,A = 1;
	while (ch < '0' || '9' < ch) {
		if (ch == '-') A = -1;
		ch = getchar();
	}
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret*A;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n; int tot = 0;
	for (int i = 1; i <= n; i++) {
		b[i] = getint();
		if (b[i] > 0) a[++tot] = b[i];
	}
	sort(a + 1,a + tot + 1);
	for (int i = 2; i <= n; i++)
		if (a[i] != a[i-1])
			a[++cur] = a[i];
	for (int i = n; i >= 1; i--)
		if (b[i] < 0) {
			int po = lower_bound(a + 1,a + cur + 1,-b[i]) - a;
			p[po].push_back(i);
		}
	for (int i = 1; i <= n; i++)
		if (b[i] > 0) {
			int Last = n;
			int po = lower_bound(a + 1,a + cur + 1,b[i]) - a;
			if (p[po].size()) 
				Last = p[po][p[po].size()-1] - 1,p[po].pop_back();
			Insert(1,1,n,i,Last,b[i]);
		}
	Work(1,1,n,1);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值