1. 程式人生 > >bzoj 4184 Shallot

bzoj 4184 Shallot

有一個一開始為空的集合,每次加入一個數或者刪除一個數,每次查詢這個集合選出若干個數異或起來的最大結果

$n \leq 100000$

sol:

學了一波線性基

大概就是

1.插入一個數(其中 v 的大小是 logn)

void add(int x)
{
    for(int i=0;i<v.size();i++) if(x > (x ^ v[i]))x ^= v[i];
    if(x)
    {
        v.push_back(x);
        for(int i=v.size()-1;i;i--) if(v[i] > v[i - 1])swap(v[i],v[i - 1
]); } }

2.查詢當前集合最大異或和

int cal()
{
    int ret = 0;
    for(int i=0;i<v.size();i++) if(ret < (ret ^ v[i])) ret ^= v[i];
    return ret;
}

其餘的操作就沒有了,合併的話是啟發式合併,刪除不資瓷,v 的大小就是當前極大線性無關集的大小

 

這道題一眼線段樹分治,然後線性基裸題

#include<bits/stdc++.h>
#define LL long long
using
namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f; for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0'; return x * f; } const int maxn = 500010; int n,a[maxn],last[maxn]; map<int,int> hsh; #define
ls (x << 1) #define rs ((x << 1) | 1) struct Base { vector<int> v; void add(int x) { for(int i=0;i<v.size();i++) if(x > (x ^ v[i]))x ^= v[i]; if(x) { v.push_back(x); for(int i=v.size()-1;i;i--) if(v[i] > v[i - 1])swap(v[i],v[i - 1]); } } int cal() { int ret = 0; for(int i=0;i<v.size();i++) if(ret < (ret ^ v[i])) ret ^= v[i]; return ret; } }; Base seg[maxn << 2],cur; inline void Insert(int x,int l,int r,int L,int R,int v) { //cout<<x<<endl; if(L <= l && r <= R) { seg[x].add(v); return; } int mid = (l + r) >> 1; if(L <= mid)Insert(ls,l,mid,L,R,v); if(R > mid)Insert(rs,mid + 1,r,L,R,v); } inline void solve(int x,int l,int r,Base cur) { for(int i=0;i<seg[x].v.size();i++)cur.add(seg[x].v[i]); if(l == r) { printf("%d\n",cur.cal()); return; } int mid = (l + r) >> 1; solve(ls,l,mid,cur);solve(rs,mid + 1,r,cur); } int main() { //freopen("20.in","r",stdin); n = read(); for(int i=1;i<=n;i++) { a[i] = read(); if(a[i] < 0)last[hsh[-a[i]]] = i - 1; else hsh[a[i]] = i; } for(int i=1;i<=n;i++) { if(a[i] < 0)continue; if(last[i] == 0)last[i] = n; Insert(1,1,n,i,last[i],a[i]); } solve(1,1,n,cur); }
View Code