BZOJ4184 : shallot

考虑离线求出每个数存在的区间,用时间线段树套链表维护每段区间内存在的数字。

然后从线段树根节点开始dfs,子节点的线性基=往父节点的线性基中插入子节点存在的数字后得到的线性基。

时间复杂度$O(31n\log n)$。

#include<cstdio>
#include<map>
std::map<int,int>vis,loc;
inline void read(int&a){
  char c;bool f=0;a=0;
  while(!((((c=getchar())>=‘0‘)&&(c<=‘9‘))||(c==‘-‘)));
  if(c!=‘-‘)a=c-‘0‘;else f=1;
  while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;
  if(f)a=-a;
}
inline void up(int&a,int b){if(a<b)a=b;}
struct Base{
  int a[31];
  Base(){for(int i=0;i<31;i++)a[i]=0;}
  inline void ins(int x){for(int i=30;~i;i--)if(x>>i&1){if(a[i])x^=a[i];else{a[i]=x;break;}}}
  inline void ask(){
    int t=0;
    for(int i=30;~i;i--)up(t,t^a[i]);
    printf("%d\n",t);
  }
};
int n,i,x,c,d,v;
struct E{int v;E*nxt;}*g[1048577],pool[8000000],*cur=pool,*p;
void ins(int x,int a,int b){
  if(c<=a&&b<=d){p=cur++;p->v=v;p->nxt=g[x];g[x]=p;return;}
  int mid=(a+b)>>1;
  if(c<=mid)ins(x<<1,a,mid);
  if(d>mid)ins(x<<1|1,mid+1,b);
}
void dfs(int x,int a,int b,Base c){
  for(p=g[x];p;p=p->nxt)c.ins(p->v);
  if(a==b){c.ask();return;}
  int mid=(a+b)>>1;
  dfs(x<<1,a,mid,c),dfs(x<<1|1,mid+1,b,c);
}
int main(){
  for(read(n),i=1;i<=n;i++){
    read(x);
    if(x>0){if(!(vis[x]++))loc[x]=i;}
    else{if(!(--vis[-x]))c=loc[-x],d=i-1,v=-x,ins(1,1,n);}
  }
  for(std::map<int,int>::iterator j=vis.begin();j!=vis.end();j++)if(j->second)c=loc[j->first],d=n,v=j->first,ins(1,1,n);
  return dfs(1,1,n,Base()),0;
}

  

时间: 2024-10-19 12:28:39

BZOJ4184 : shallot的相关文章

线段树分治

2014徐寅展论文<线段树在一类分治问题上的应用>读后感. 线段树分治 线段树分治其实就是有撤销操作的时间分治. 题目让你维护一些信息,每次可以询问,可以执行一种操作,也可以将之前的某个这种操作撤回. 操作容易维护,但撤回操作不容易维护. 需要将操作,询问都离线下来.将时间轴画出来,那么每个操作只在时间轴上的一个区间内生效. 用线段树给这个区间打上这个操作的标记,维护信息. TJOI2018 数学计算 小豆现在有一个数x,初始值为1. 小豆有Q次操作,操作有两种类型: m: x = x * m

【bzoj4184】shallot 线段树+高斯消元动态维护线性基

题目描述 小苗去市场上买了一捆小葱苗,她突然一时兴起,于是她在每颗小葱苗上写上一个数字,然后把小葱叫过来玩游戏. 每个时刻她会给小葱一颗小葱苗或者是从小葱手里拿走一颗小葱苗,并且 让小葱从自己手中的小葱苗里选出一些小葱苗使得选出的小葱苗上的数字的异或和最大. 这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为Oi选手的你,你能帮帮他吗? 你只需要输出最大的异或和即可,若小葱手中没有小葱苗则输出0. 输入 第一行一个正整数n表示总时间:第二行n个整数a1,a2...an,

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

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

shallot夏洛特

================================================================= ================================================================= ================================================================= ====================================================

BZOJ 4184: shallot

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

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 4184: shallot」

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

一款纯css实现的垂直时间线效果

今天给大家分享一款纯css实现的垂直时间线效果.垂直时间线适合放在类似任务时间安排的网页上.该实现采用了蓝色作为主题色,界面效果还不错.一起看下效果图: 在线预览   源码下载 实现的代码. html代码: <div class="container"> <header class="clearfix"> <span>Blueprint <span class="bp-icon bp-icon-about"

BZOJ 4311 向量

shallot+向量集 混合版? 首先我们考虑每个向量的存在时间为[L,R] 那么我们知道任意一个区间在线段树上最多被分解成logn个区间 那么我们可以像shallot一样进行区间覆盖 注意到本题的查询是在凸壳上完成的,而凸壳不像shallot的线性基一样有固定的时间复杂度 但是本题的查询是可分离的,那么我们不需要将向量下传,只需要在线段树的每一层做凸壳即可 查询时每走一层对该层三分取最优解,建造凸壳和三分方法同向量集 QAQ 上午因为排序不小心写反了符号调了好久 QAQ 时间复杂度O(nlog