Bzoj4184 shallot

用 线段树 维护带有删除操作的线性基

阅读全文大概需要 1分钟
本文总阅读量
Posted by yjjr's blog on March 15, 2018

标签:线性基,线段树,CDQ分治

题目

题目传送门

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\]

分析

考试的时候现学了线性基,刺激qwq


因为线性基不支持删除操作,所以我们考虑离线

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

这样就可以化解删除操作了

具体方法是给线段树上的每一个节点都开一个vector,vector里维护的就是线性基

每次更新到一整块区间就在线性基中加入这个数,并维护线性基

查询的时候将每个点到根的路径上的所有线性基扔进一个新开的vector,维护的同时贪心就好了


官方题解给出的是CDQ分治,时间复杂度为\(O(31n\log n)\)

code

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#define reg(x) for(int i=last[x];i;i=e[i].next)
using namespace std;
inline ll read(){
	ll f=1,x=0;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;
}
//**********head by yjjr**********
#define lson (x<<1)
#define rson (x<<1|1)
#define mid ((l+r)>>1)
#define mp make_pair
#define pb push_back
const int maxn=5e5+6;
int n,last[maxn],x[maxn],y;
map<int,int> Map;
struct line{
    vector<int>v;
    inline int insert(int x){
        for(int i=0;i<v.size();i++)if((x^v[i])<x)x^=v[i];
        if(x){
            v.pb(x);
            for(int i=v.size()-1;i;i--)if(v[i]>v[i-1])swap(v[i],v[i-1]);
        }
        return x;
    }
    inline int querymax(){
        int re=0;
        for(int i=0;i<v.size();i++)if((re^v[i])>re)re^=v[i];
        return re;
    }
}s[maxn<<2],F;
void modify(int x,int l,int r,int ql,int qr,int v){
    if(ql<=l&&r<=qr){s[x].insert(v);return;}
    if(ql<=mid)modify(lson,l,mid,ql,qr,v);
    if(qr>mid)modify(rson,mid+1,r,ql,qr,v);
}
void query(int l,int r,int x,line q){
    for(int i=0;i<s[x].v.size();i++)q.insert(s[x].v[i]);
    if(l==r){
        printf("%d\n",q.querymax());
        return;
    }
    query(l,mid,lson,q),query(mid+1,r,rson,q);
}
int main()
{
	n=read();
	rep(i,1,n){
		x[i]=read();
		if(x[i]<0)y=Map[-x[i]],last[y]=i-1;else Map[x[i]]=i;
	}
    rep(i,1,n){
    	if(x[i]<0)continue;
    	if(!last[i])last[i]=n;
    	modify(1,1,n,i,last[i],x[i]);
    }
    query(1,n,1,F);
    return 0;
}
本文可以转载,但必须附上原文链接,否则你会终生找不到妹子!!!欢迎关注我的CSDN: ahyjjr