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

题意

  给定时长 $n$ , 每个时刻有某个元素出现或者消失, 求每个时刻所有元素的最大异或值.

  $n \le 500000$ .

分析

  通过 map 或者 hash , 我们可以知道 $O(n)$ 个 "一个元素 $x$ 在 $[l, r]$ " 出现的信息.

  对时间建立线段树, 每个节点开一个 vector , 对区间 $[l, r]$ 对应的所有节点插入一个 $x$ .

  对线段树进行 DFS , 同时动态维护线性基.

实现

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <map>
using namespace std;

#define F(i, a, b) for (register int i = (a); i <= (b); i++)
#define P(i, a, b) for (register int i = (a); i >= (b); i--)

const int N = 1500000;
const int E = 10000005;

int n; map<int, int> vis;
int M, tot, hd[N], nx[E], v[E];
int s[N], top, b[35];

inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f;
}

inline void Ins(int x, int w) { nx[++tot] = hd[x], hd[x] = tot, v[tot] = w; }
inline void Fill(int L, int R, int w) {
    for (L--, R++, L += M, R += M; L^R^1; L >>= 1, R >>= 1) {
        if (!(L&1)) Ins(L^1, w);
        if (R&1) Ins(R^1, w);
    }
}

inline void Insert(int w) {
    P(i, 30, 0) if (w>>i&1)
        if (!b[i]) { b[s[++top] = i] = w; break; } else w ^= b[i];
}
inline int Max(void) { int res = 0; P(i, 30, 0) res = max(res, res ^ b[i]); return res; }
void Tsunami(int x, int L, int R) {
    if (R < 1 || L > n) return;

    int t = top;
    for (int k = hd[x]; k > 0; k = nx[k])
        Insert(v[k]);

    if (L == R)
        printf("%d\n", Max());
    else {
        int M = (L+R)>>1;
        Tsunami(x<<1, L, M);
        Tsunami(x<<1|1, M+1, R);
    }

    for (; top > t; s[top--] = 0)
        b[s[top]] = 0;
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4184.in", "r", stdin);
        freopen("bzoj4184.out", "w", stdout);
    #endif

    n = rd(); for (M = 1; M < n+2; M <<= 1);
    F(i, 1, n) {
        int x = rd();
        if (x > 0) vis[x] = i; else x = -x, Fill(vis[x], i-1, x), vis[x] = 0;
    }
    for (map<int, int>::iterator it = vis.begin(); it != vis.end(); it++)
        if (it -> second > 0)
            Fill(it -> second, n, it -> first);

    Tsunami(1, 0, M-1);

    return 0;
}
时间: 2024-08-07 21:16:54

[BZOJ 4184] shallot 以时间为基底建线段树的相关文章

FZU2105 Digits Count(按位建线段树)题解

题意: 给出区间与.或.异或\(x\)操作,还有询问区间和. 思路: 因为数比较小,我们给每一位建线段树,这样每次只要更新对应位的答案. 与\(0\)和或\(1\)相当于重置区间,异或\(1\)相当于翻转区间,那么设出两个\(lazy\)搞一下.注意父区间\(pushdown\)重置标记时,子区间的翻转标记要清空. 代码: #include <map> #include <set> #include <queue> #include <cmath> #inc

BZOJ 4184: shallot

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

「bzoj 4184: shallot」

权限题 线段树分治加线性基 首先这个题要求删除线性基肯定是没法处理的 于是我们套上一个线段树分治 线段树分治就是一种能够避免删除的神仙操作 我们发现询问是对一个时间的单点询问,而每一个数存在的时间却是一个区间 我们求出来每个数的存在区间,每一个区间对应在线段树上并不会超过\(logn\)段 我们就把这些存活区间插入到线段树里去,标记永久化一下 由于一个线性基也就是\(logn\)的空间,所以我们直接一路把线性基搞下来,中间把标记插入线性基就好了 到叶子结点我们就可以处理询问了 代码 #inclu

[BZOJ 3218] A + B Problem 【可持久化线段树 + 网络流】

题目连接:BZOJ - 3218 题目分析 题目要求将 n 个点染成黑色或白色,那么我们可以转化为一个最小割模型. 我们规定一个点 i 最后属于 S 集表示染成黑色,属于 T 集表示染成白色,那么对于每个点 i 就要连边 (S, i, B[i]) 和 (i, T, W[i]). 这样,如果一个点属于 S 集,就要割掉与 T 相连的边,就相当于失去了染成白色的收益. 我们再来考虑 “奇怪的点”,一个点 i 变成奇怪的点的条件是:i 是黑色且存在一个白色点 j 满足 j < i && L

[BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】

题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经典模型. 我们线段树的一个节点表示一个区间的联通性,有 6 个 bool 值,表示这个区间的 4 个角上的点之间的联通性. 然后用两个子区间的联通性和两个子区间之间的连边情况合并出整个区间的联通性. 修改某条边时,先在边的数组中修改,然后从这条边所在的点的线段树叶子开始向上 Update . 询问两

bzoj 1835 [ZJOI2010]base 基站选址(DP+线段树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1835 [题意] 有n个村庄,每个村庄位于d[i],要求建立不多于k个基站,在第i个村庄建基站的费用为c[i],如果在距离村i不超过s[i]内有基站则该村被覆盖,村i不被覆盖的补偿费为w[i],求最少花费. [思路] 设f[i][j]表示第i个村建第j个基站的最小花费,则有转移式: f[i][j]=min{ f[k][j-1]+cost(k,i) } + c[i] ,j-1<=k<=

BZOJ 1651: [Usaco2006 Feb]Stall Reservations 专用牛棚( 线段树 )

线段树.. -------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; i++ ) #define c

bzoj 2733 永无乡 - 并查集 - 线段树

永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输

bzoj 1503: [NOI2004]郁闷的出纳员 -- 权值线段树

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MB Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可能把他们的工资扣除一个相同的量.我真不知道除了调工资他还做什么其它事情.工资的频繁调