BZOJ4184: shallot

BZOJ4184: shallot

线性基·线段树

题解:

又是一道神题!
然而蒟蒻只能抄题解,还抄漏了一句。。。

一个数字的出现时间是一段区间 [l,r] ,可以开一棵线段树,把 [l,r] 对应的线段树节点上的vector里加上这个数。
最后dfs一次,参数传一个线性基(不是引用),把当前点vector里的都加进去,再往下dfs。
这样到达叶节点的线性基就包含了这个点时存在的数,输出一下XOR最大值即可。

也可以不实际开出线段树来,采用一种类似分治的方式。
原理一样,详见代码。

Code:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;
const int LOG = 30;
const int N = 500005;

int n;
map<int,int> last;

inline void read(int &num){
    num=0; char c; int bo=1;
    while(!isdigit(c=getchar()) && c!='-');
    if(c=='-') bo=-1;
    else num=c-'0';
    while(isdigit(c=getchar())) num=num*10+c-'0';
    num*=bo;
}

struct Data{
    int l,r,x;
    Data(int _l,int _r,int _x):l(_l),r(_r),x(_x){}
}; 

struct LB{
    int b[LOG+1];
    LB(){ memset(b,0,sizeof(b)); }
    void insert(int x){
        for(int i=LOG;i>=0;i--){
            if((x>>i)&1){
                if(!b[i]){ b[i]=x; break; }
                x^=b[i];
            }
        }
    }
    int getMax(){
        int ans=0;
        for(int i=LOG;i>=0;i--){
            if((ans^b[i])>ans) ans^=b[i];
        }
        return ans;
    }
};


void work(int l,int r,vector<Data> d,LB lb){
    if(l>r) return;
//  D(l); D(r); E; 
    for(int i=0;i<d.size();i++){
        if(d[i].l==l && d[i].r==r){
            lb.insert(d[i].x);
        }
    }
    if(l==r){
        printf("%d\n",lb.getMax());
        return;
    }
    int mid=(l+r)>>1;
    vector<Data> ld,rd;
    for(int i=0;i<d.size();i++){
        if(d[i].l==l && d[i].r==r) continue;  //漏了这一句,TLE了半天。。。
        if(d[i].l<=mid) ld.push_back(Data(d[i].l,min(mid,d[i].r),d[i].x));
        if(d[i].r>mid) rd.push_back(Data(max(mid+1,d[i].l),d[i].r,d[i].x));
    }
    work(l,mid,ld,lb);
    work(mid+1,r,rd,lb);
}

int main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    read(n); int a;
    vector<Data> d; LB lb;
    for(int i=1;i<=n;i++){
        read(a);
        if(a>0) last[a]=i;
        else{ a=-a; d.push_back(Data(last[a],i-1,a)); last[a]=0; }
    }
    for(map<int,int>::iterator it=last.begin();it!=last.end();it++){
        if(it->second){
            d.push_back(Data(it->second,n,it->first));
        }
    }
    work(1,n,d,lb);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值