bzoj 4184 shallot(线段树分治+线性基)

题解:

  • 题目要求维护带插入和删除的整体异或最大值
  • 整体异或最大值容易想到线性基,但线性基支持动态能插入而不支持删除。
  • 可以发现每个数出现的时间是一段或几段连续的区间。
  • 于是我们可以对时间建线段树,线段树的每个区间用$vector$储存在这段时间里出现的数,这样就避免了删除操作。
  • 在统计答案时从线段树根节点遍历到叶子节点,同时维护一个线性基,将经过的节点$vector$中的数插入到线性基中,最后在叶子节点询问异或最大值即可。
查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5+5;
const int mod = 1e9+7;
ll qpow(ll a,ll b){ll res=1;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
struct LinearBasis
{
    int a[32];
    LinearBasis(){init();};
    void init(){memset(a,0,sizeof(a));}
    void Insert(int x){
        for(int i = 30;i >= 0;--i){
            if(!(x>>i&1))continue;
            if(a[i])x^=a[i];
            else {
                for(int j = 0;j < i;++j){
                    if(x&(1<<j))x^=a[j];
                }
                for(int j = i+1;j <= 30;++j){
                    if(a[j]&(1<<i))a[j]^=x;
                }
                a[i]=x;
                return;
            }
        }
    }
    int query(){
        int ans = 0;
        for(int i = 0;i <= 30;++i)ans^=a[i];
        return ans;
    }
    void merge(const LinearBasis &b){
        for(int i = 0;i <= 30;++i)Insert(b.a[i]);
    }
};
map<int,int>mp;
int ans[maxn];
struct Segment_tree
{
    vector<int>v[maxn<<2];
    void Insert(int root,int l,int r,int il,int ir,int x){
        if(l>=il&&r<=ir){
            v[root].push_back(x);
            return;
        }
        int mid = l+r>>1;
        if(il<=mid)Insert(root<<1,l,mid,il,ir,x);
        if(ir>mid)Insert(root<<1|1,mid+1,r,il,ir,x);
        return;
    }
    void dfs(int root,int l,int r,LinearBasis lb){
        for(auto i:v[root])lb.Insert(i);
        if(l==r){
            ans[l]=lb.query();
            return;
        }
        int mid = l+r>>1;
        dfs(root<<1,l,mid,lb);
        dfs(root<<1|1,mid+1,r,lb);
    }
}sg;
int main()
{
#ifndef ONLINE_JUDGE
    freopen("simple.in", "r", stdin);
    freopen("simple.out", "w", stdout);
#endif
    int n;
    scanf("%d",&n);
    for(int i = 1,a;i <= n;++i){
        scanf("%d",&a);
        if(a>0)mp[a]=i;
        else {
            sg.Insert(1,1,n,mp[-a],i-1,-a);
            mp[-a]=0;
        }
    }
    for(auto i:mp){
        if(i.first>0&&i.second>0)sg.Insert(1,1,n,i.second,n,i.first);
    }
    LinearBasis lb;
    sg.dfs(1,1,n,lb);
    for(int i = 1;i <= n;++i)printf("%d\n",ans[i]);
    return 0;
}
posted @ 2020-06-01 21:27  tryatry  阅读(103)  评论(0编辑  收藏  举报