您的位置:首页 > 其它

BZOJ 4184 shallot

2016-03-29 15:36 218 查看
好神的一道题目

某只萌萌哒神犇给我安利了一发

首先如果没有删除,我们会做,因为这是裸的线性基

那么对于任意的时间,我们只需要知道有多少个数且这些数是什么就可以维护线性基了

我们考虑对时间搞出一颗线段树

对于任意的数,其存在的时间是一段区间,那么我们就可以在线段树上做区间覆盖

可以证明,在打标记的情况下,最多被分解为log(n)个区间

那么我们只需要O(nlog(n))的空间就可以记录每个时间上面的数是什么了

最后对线段树做一遍DFS,在过程中动态维护线性基就可以知道答案了

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

const int maxn=2000010;
int n,x;
set<pair<int,int> >S;
vector<int>V[maxn];
int L[maxn],R[maxn],mid[maxn];
struct Ans{
int Num[32];
Ans(){memset(Num,0,sizeof(Num));}
void push(int v){
for(int i=30;i>=0;--i){
if(v>>i&1){
if(!Num[i]){Num[i]=v;break;}
else{v^=Num[i];}
}
}return;
}
int ask(){
int ans=0;
for(int i=30;i>=0;--i){
if((ans^Num[i])>ans)ans^=Num[i];
}return ans;
}
};

void build(int o,int l,int r){
L[o]=l;R[o]=r;
if(l==r)return;
mid[o]=(l+r)>>1;
build(o<<1,L[o],mid[o]);
build(o<<1|1,mid[o]+1,R[o]);
}
void Get_modify(int o,int x,int y,int v){
if(L[o]>=x&&R[o]<=y){V[o].push_back(v);return;}
if(y<=mid[o])Get_modify(o<<1,x,y,v);
else if(x>mid[o])Get_modify(o<<1|1,x,y,v);
else {Get_modify(o<<1,x,y,v);Get_modify(o<<1|1,x,y,v);}
}
void Get_ans(int o,Ans now){
int sz=V[o].size();
for(int i=0;i<sz;++i)now.push(V[o][i]);
if(L[o]==R[o]){printf("%d\n",now.ask());return;}
Get_ans(o<<1,now);Get_ans(o<<1|1,now);
}

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


shallot
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: