「bzoj 4184: shallot」

权限题

线段树分治加线性基

首先这个题要求删除线性基肯定是没法处理的

于是我们套上一个线段树分治

线段树分治就是一种能够避免删除的神仙操作

我们发现询问是对一个时间的单点询问,而每一个数存在的时间却是一个区间

我们求出来每个数的存在区间,每一个区间对应在线段树上并不会超过\(logn\)段

我们就把这些存活区间插入到线段树里去,标记永久化一下

由于一个线性基也就是\(logn\)的空间,所以我们直接一路把线性基搞下来,中间把标记插入线性基就好了

到叶子结点我们就可以处理询问了

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define LL long long
#define re register
#define maxn 500005
inline int read() {
    char c=getchar();int x=0,r=1;
    while(c<'0'||c>'9') {if(c=='-') r=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3ll)+(x<<1ll)+c-48,c=getchar();return x*r;
}
struct Base {
    int lb[33];
    inline void ins(int x) {
        for(re int i=31;i>=0;--i)
        if(x>>i&1) {
            if(!lb[i]) {lb[i]=x;return;}
            x^=lb[i];
        }
    }
    inline int query() {
        int ans=0;
        for(re int i=31;i>=0;--i) if((ans^lb[i])>ans) ans^=lb[i];
        return ans;
    }
}A;
std::vector<int> v[maxn*3];
int n,m,sz,tot;
int lst[maxn],nxt[maxn],L[maxn],R[maxn],val[maxn],ans[maxn],c[maxn],a[maxn];
inline int find(int x) {
    int l=1,r=sz;
    while(l<=r) {
        int mid=l+r>>1;
        if(c[mid]==x) return mid;
        if(c[mid]<x) l=mid+1;else r=mid-1;
    }
    return 0;
}
void change(int l,int r,int x,int y,int val,int i) {
    if(x<=l&&y>=r) {v[i].push_back(val);return;}
    int mid=l+r>>1;
    if(x<=mid) change(l,mid,x,y,val,i<<1);
    if(y>=mid+1) change(mid+1,r,x,y,val,i<<1|1);
}
void solve(int l,int r,int i,Base A) {
    for(re int j=0;j<v[i].size();j++)
        A.ins(v[i][j]);
    if(l==r) {
        ans[l]=A.query();
        return;
    }
    int mid=l+r>>1;
    solve(l,mid,i<<1,A);solve(mid+1,r,i<<1|1,A);
}
int main() {
    n=read();
    for(re int i=1;i<=n;i++) a[i]=read();
    for(re int i=1;i<=n;i++) c[i]=((a[i]>0)?a[i]:-1*a[i]);
    std::sort(c+1,c+n+1);sz=std::unique(c+1,c+n+1)-c-1;
    for(re int i=1;i<=n;i++) {
        int x=find((a[i]>0)?a[i]:-1*a[i]);
        if(a[i]>0) {
            nxt[i]=lst[x],lst[x]=i;
        }
        else {
            L[++tot]=lst[x];R[tot]=i-1;val[tot]=-1*a[i];
            lst[x]=nxt[lst[x]];
        }
    }
    for(re int i=1;i<=sz;i++)
        while(lst[i]) L[++tot]=lst[i],R[tot]=n,val[tot]=c[i],lst[i]=nxt[lst[i]];
    for(re int i=1;i<=tot;i++)
        change(1,n,L[i],R[i],val[i],1);
    solve(1,n,1,A);
    for(re int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/asuldb/p/10518183.html

时间: 2024-10-28 15:43:51

「bzoj 4184: shallot」的相关文章

BZOJ 4184: shallot

Description 在某时刻加入或删除一个点,问每个时刻的集合中能异或出来的最大值是多少. Sol 线段树+按时间分治+线性基. 把一个数字的存在时间挂在线段树的区间上,不超过 \(logn\) 个区间,所以总和不超过 \(nlogn\) 个节点信息. 然后从上往下走遍历整个线段树,每次到根节点统计一下答案,这里跟线性基有些不同,线性基转置矩阵就是普通的高斯消元,这时候维护线性基,每次插入一个数,更新的贡献,统计答案的时候从上往下贪心,选一个最大值,而不是回带... Code /******

[BZOJ 4184] shallot 以时间为基底建线段树

题意 给定时长 $n$ , 每个时刻有某个元素出现或者消失, 求每个时刻所有元素的最大异或值. $n \le 500000$ . 分析 通过 map 或者 hash , 我们可以知道 $O(n)$ 个 "一个元素 $x$ 在 $[l, r]$ " 出现的信息. 对时间建立线段树, 每个节点开一个 vector , 对区间 $[l, r]$ 对应的所有节点插入一个 $x$ . 对线段树进行 DFS , 同时动态维护线性基. 实现 #include <cstdio> #incl

bzoj 4184: shallot (线段树维护线性基)

题面 \(solution:\) \(code:\) #include<iostream> #include<cstdio> #include<iomanip> #include<algorithm> #include<cstring> #include<cstdlib> #include<ctime> #include<cmath> #include<vector> #include<que

「BZOJ 4451」「CERC 2015」Frightful Formula

给 $n \times n(n \le 200000)$ 的方格,第一列.第一行 $f[1, i], f[i, 1] (\le 10 ^ 6)$ 和 $a, b, c(\le 10 ^ 6)$ ,转移方式为 $f[i, j] = a f[i, j-1] + b f[i-1, j] + c$ ,求 $f[n, n] \mod 1000003$ . 考虑每个位置的贡献. 第一行.第一列的贡献直接 $O(n)$ 算,注意第一步的方向是确定的. 对于其余位置 $(i, j)$ ,贡献为 $\begin{

LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例

二次联通门 : LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 /* LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 很显然 贪心方程哦不 dp方程为 f[i][j]=f[i-1][j-k*k] 但是这样的话复杂度就是O(N ^ 5) 那么就用bitset优化一下 就ok了 */ #include <iostream> #include <cstdio> #include <bitset> void

Linux 小知识翻译 - 「编译器和解释器」

这次聊聊「编译器和解释器」. 编程语言中,有以C为代表的编译型语言和以Perl为代表的解释型语言.不管是哪种,程序都是以人类能够理解的形式记录的,这种形式计算机是无法理解的. 因此,才会有编译器和解释器. 对于编译型语言,是使用编译器将人类可读的代码转换为机器能够理解的「机器语言」文件,然后通过执行这个「机器语言」文件来实现程序的执行. 另一方面,对于解释型语言,是使用解释器将人类可读的代码逐行解释,一边解释一边执行这个程序.(这里的解释是将代码解释成机器语言,让计算机能够理解) 甚至有的语言既

「每日一歌」微信公众号

最近弄了一个微信公众号,叫做「每日一歌」(微信ID:Song_Daily).每天早上6点,分享一首经典歌曲.欢迎各位来关注! 音乐,广义而言,就是指任何以声音组成的艺术.英文Music一词源于古希腊语的μουσικ?(mousike),意即缪斯(muse)女神的艺术.而中文的音乐二字,许慎<说文解字>解释为“音,声也.生于心,有节于外,谓之音.”认为音乐和声音的区别,在于音乐需要透过人心去想像和创造.音乐可分为创作.演奏.聆听三个过程,在不同文化和社会,对于音乐的过程及其重要性都有不同的理解.

LibreOJ「LibreOJ β Round #4」 游戏

二次联通门 : LibreOJ「LibreOJ β Round #4」 游戏 /* LibreOJ「LibreOJ β Round #4」 游戏 找找规律就会发现.. 当有X的时候,答案跟X个数的奇偶有关 否则就求一下逆序对就好了.. 由于SB的错误..WA了3发才过 然后就签完到走人了 */ #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #defi

LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意

二次联通门 : LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意 /* LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意 本想打个暴力找找规律 结果交上去就A了... 读入所有数 处理出前缀和 然后枚举区间长度 处理处1~n的答案 后O(1)查询即可 复杂度O(n^2 + m) */ #include <iostream> #include <cstring> #include <cstdio> voi