【BZOJ3217】ALOEXT

Description

taorunz平时最喜欢的东西就是可移动存储器了……只要看到别人的可移动存储器,他总是用尽一切办法把它里面的东西弄到手。

突然有一天,taorunz来到了一个密室,里面放着一排可移动存储器,存储器里有非常珍贵的OI资料……不过比较特殊的是,每个存储器上都写着一个非负整数。taorunz很高兴,要把所有的存储器都拿走(taorunz的智商高达500,他一旦弄走了这里的所有存储器,在不久到来的AHOI和NOI中……你懂的)。不过这时有一个声音传来:“你只能拿走这里的一个存储器,而且还不能直接拿,你需要指定一段区间[l, r],满足l<r,然后在第l个和第r个存储器之间选一个拿走,你能获得的知识增加量等于区间[l, r]中所有存储器上写的整数的次大值与你拿走的这个存储器上写的整数作按位异或运算的结果。”

问题是,这里的可移动存储器数量太多,而且,它们还在不断地发生变化,有时候天上会掉下来一个新的存储器,并插入到这一排存储器中,有时候某个存储器会不明原因消失,有时候某个存储器上写的整数变化了。taorunz虽然智商很高,但也无法应对如此快的变化,他指定了许多段区间,让你帮他找出如果在这个区间中拿走存储器,他能获得的最多的知识是多少。

Input

第一行两个整数N、M,表示一开始的存储器数和后面发生的事件数。

第二行N个非负整数,表示一开始从左到右每个存储器上写的数字。注意,存储器从0开始编号,也就是最左边的存储器是第0个。

接下来M行,每行描述一个事件,有4种可能的事件。

(1)I x y:表示天上掉下来一个写着数字y的存储器,并插入到原来的第x个存储器之前,如果x等于原来存储器的个数,则插入到末尾;

(2)D x:表示第x个存储器消失;

(3)C x y:表示第x个存储器上写的数字变为y;

(4)F l r:表示taorunz指定区间[l, r],让你告诉他最多能获得多少知识。

注意,本题强制在线,也就是事件中出现的所有数字都进行了加密,数字s表示的真实值是

对于I、D、C事件中的x及F事件中的l、r:(s+last_ans) mod n0;

对于I、C事件中的y:(s+last_ans) mod 1048576。

其中n0为目前存储器个数,last_ans为上一个F事件的结果,如果前面尚未发生F事件,则last_ans=0。

Output

对于每个F事件,输出结果。

Sample Input

5 10
2 6 3 8 7
F 1 4
I 2 1048565
I 0 1048566
D 3
F 3 0
I 3 1048569
D 5
C 1 1048570
F 1 2
F 2 1

Sample Output

15
7
4
7

HINT

1<=N, M<=100000。所有F事件满足l<r。
本题共有5组数据,除1组为随机数据外,其它数据均为人工构造。

题解:直接替罪羊树套Trie树。外层直接在替罪羊树上维护最大值和次大值,然后查询时将区间中对应的log个Trie树提取出来,一起跑一个贪心即可。

替罪羊树的删除有两种写法,一种是将前驱或后继提上来,一种是打标记。我采取的是打标记的方式,虽然特判比较多~看代码吧。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn=200010;
const int mod=1048576;
int n0,n,m,ans,tot,root,last,flast;
struct trie
{
int ch[2],siz;
}s[30000010];
struct node
{
int s1,s2;
node(){}
node(int a,int b){s1=a,s2=b;}
}sec;
struct tzy
{
int ls,rs,siz,msiz,rt,val,fa;
node sm;
}t[maxn];
int p[maxn],pp[maxn];
char str[5];
queue<int> q;
void pushup(node &x,node y)
{
if(y.s1>x.s1) x.s2=max(x.s1,y.s2),x.s1=y.s1;
else x.s2=max(x.s2,y.s1);
}
void insert(int &x,int y,int val)
{
if(!x) x=q.front(),q.pop();
int u=x,i,d;
for(i=1<<20;i;i>>=1)
{
d=((y&i)>0);
if(!s[u].ch[d]) s[u].ch[d]=q.front(),q.pop();
u=s[u].ch[d],s[u].siz+=val;
}
}
int query(int val)
{
int i,j,d,ret=0;
for(i=1<<20;i;i>>=1)
{
d=!(val&i);
for(j=1;j<=p[0];j++)
{
if(s[s[p[j]].ch[d]].siz)
{
ret|=i;
break;
}
}
if(j>p[0]) d^=1;
for(j=1;j<=p[0];j++) p[j]=s[p[j]].ch[d];
}
for(i=1;i<=pp[0];i++) ret=max(ret,val^pp[i]);
return ret;
}
int build(int l,int r,int from)
{
if(l>r) return 0;
int mid=(l+r)>>1,x=p[mid],i;
t[x].ls=build(l,mid-1,x),t[x].rs=build(mid+1,r,x),t[x].siz=t[x].msiz=r-l+1,t[x].rt=0,t[x].fa=from;
t[x].sm.s1=t[x].val,t[x].sm.s2=-1;
if(t[x].ls) t[t[x].ls].fa=x,pushup(t[x].sm,t[t[x].ls].sm);
if(t[x].rs) t[t[x].rs].fa=x,pushup(t[x].sm,t[t[x].rs].sm);
for(i=l;i<=r;i++) insert(t[x].rt,t[p[i]].val,1);
return x;
}
void del(int &x)
{
if(!x) return ;
del(s[x].ch[0]),del(s[x].ch[1]),s[x].siz=0,q.push(x),x=0;
}
void dfs(int x)
{
if(!x) return ;
dfs(t[x].ls);
if(t[x].val>=0) p[++p[0]]=x;
dfs(t[x].rs),del(t[x].rt);
}
void add(int &x,int y,int from)
{
if(!x)
{
x=n,t[x].sm.s1=t[x].val,t[x].sm.s2=-1,t[x].ls=t[x].rs=t[x].rt=0,t[x].fa=from,t[x].siz=t[x].msiz=1;
insert(t[x].rt,t[x].val,1);
return ;
}
if(y>=t[t[x].ls].siz+(t[x].val>=0)) add(t[x].rs,y-t[t[x].ls].siz-(t[x].val>=0),x);
else add(t[x].ls,y,x);
insert(t[x].rt,t[n].val,1),t[x].siz++,pushup(t[x].sm,t[n].sm);
t[x].msiz=t[t[x].ls].msiz+t[t[x].rs].msiz+1;
if(t[t[x].ls].msiz>t[x].msiz*0.75||t[t[x].rs].msiz>t[x].msiz*0.75) last=x,flast=from,t[x].msiz=t[x].siz;
}
void find(int x,int a,int b)
{
if(!x||a>b) return ;
if(a==1&&b==t[x].siz)
{
pushup(sec,t[x].sm);
p[++p[0]]=t[x].rt;
return ;
}
if(a>t[t[x].ls].siz+(t[x].val>=0)) find(t[x].rs,a-t[t[x].ls].siz-(t[x].val>=0),b-t[t[x].ls].siz-(t[x].val>=0));
else if(b<=t[t[x].ls].siz) find(t[x].ls,a,b);
else
{
find(t[x].ls,a,t[t[x].ls].siz);
if(t[x].val>=0) pp[++pp[0]]=t[x].val,pushup(sec,node(t[x].val,-1));
find(t[x].rs,1,b-t[t[x].ls].siz-(t[x].val>=0));
}
}
int getval(int x,int y)
{
if(y>t[t[x].ls].siz+(t[x].val>=0)) return getval(t[x].rs,y-t[t[x].ls].siz-(t[x].val>=0));
if(y<=t[t[x].ls].siz) return getval(t[x].ls,y);
return t[x].val;
}
void dec(int x,int y,int z)
{
if(y>t[t[x].ls].siz+(t[x].val>=0)) dec(t[x].rs,y-t[t[x].ls].siz-(t[x].val>=0),z);
else if(y<=t[t[x].ls].siz) dec(t[x].ls,y,z);
else t[x].val=-1;
t[x].sm.s1=t[x].val,t[x].sm.s2=-1,t[x].siz--;
insert(t[x].rt,z,-1);
if(t[x].ls) pushup(t[x].sm,t[t[x].ls].sm);
if(t[x].rs) pushup(t[x].sm,t[t[x].rs].sm);
}
void modify(int x,int y,int a,int b)
{
if(y>t[t[x].ls].siz+(t[x].val>=0)) modify(t[x].rs,y-t[t[x].ls].siz-(t[x].val>=0),a,b);
else if(y<=t[t[x].ls].siz) modify(t[x].ls,y,a,b);
else t[x].val=b;
insert(t[x].rt,a,-1),insert(t[x].rt,b,1);
t[x].sm.s1=t[x].val,t[x].sm.s2=-1;
if(t[x].ls) pushup(t[x].sm,t[t[x].ls].sm);
if(t[x].rs) pushup(t[x].sm,t[t[x].rs].sm);
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
n0=n=rd(),m=rd();
int i,a,b,c,u;
for(i=1;i<=30000000;i++) q.push(i);
for(i=1;i<=n;i++) t[i].val=rd(),p[i]=i;
root=build(1,n,0);
for(i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='I')
{
a=(rd()+ans)%n0,b=(rd()+ans)%mod,n0++;
t[++n].val=b,last=0,add(root,a,0);
if(last)
{
p[0]=0,dfs(last);
if(!flast) root=build(1,p[0],0);
else if(last==t[flast].ls) t[flast].ls=build(1,p[0],flast);
else t[flast].rs=build(1,p[0],flast);
for(u=last;u;u=t[u].fa) t[u].msiz=t[t[u].ls].msiz+t[t[u].rs].msiz+1;
}
}
if(str[0]=='D')
{
a=(rd()+ans)%n0+1,b=getval(root,a),n0--;
dec(root,a,b);
}
if(str[0]=='C')
{
a=(rd()+ans)%n0+1,b=(rd()+ans)%mod,c=getval(root,a);
modify(root,a,c,b);
}
if(str[0]=='F')
{
a=(rd()+ans)%n0+1,b=(rd()+ans)%n0+1;
p[0]=pp[0]=0,sec.s1=sec.s2=-1,find(root,a,b);
ans=query(sec.s2);
printf("%d\n",ans);
}
}
return 0;
}//5 10 2 6 3 8 7 F 1 4 I 2 1048565 I 0 1048566 D 3 F 3 0 I 3 1048569 D 5 C 1 1048570 F 1 2 F 2 1

【BZOJ3217】ALOEXT 替罪羊树+Trie树的更多相关文章

  1. Atitit 常见的树形结构 红黑树  二叉树   B树 B+树  Trie树 attilax理解与总结

    Atitit 常见的树形结构 红黑树  二叉树   B树 B+树  Trie树 attilax理解与总结 1.1. 树形结构-- 一对多的关系1 1.2. 树的相关术语: 1 1.3. 常见的树形结构 ...

  2. 字典树(Trie树)的实现及应用

    >>字典树的概念 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树.与二叉查找树不同,Trie树的 ...

  3. [POJ] #1002# 487-3279 : 桶排序/字典树(Trie树)/快速排序

    一. 题目 487-3279 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 274040   Accepted: 48891 ...

  4. 洛谷$P4585\ [FJOI2015]$火星商店问题 线段树+$trie$树

    正解:线段树+$trie$树 解题报告: 传送门$QwQ$ $umm$题目有点儿长我先写下题目大意趴$QwQ$,就说有$n$个初始均为空的集合和$m$次操作,每次操作为向某个集合内加入一个数$x$,或 ...

  5. luoguP6623 [省选联考 2020 A 卷] 树(trie树)

    luoguP6623 [省选联考 2020 A 卷] 树(trie树) Luogu 题外话: ...想不出来啥好说的了. 我认识的人基本都切这道题了. 就我只会10分暴力. 我是傻逼. 题解时间 先不 ...

  6. [转载]字典树(trie树)、后缀树

    (1)字典树(Trie树) Trie是个简单但实用的数据结构,通常用于实现字典查询.我们做即时响应用户输入的AJAX搜索框时,就是Trie开始.本质上,Trie是一颗存储多个字符串的树.相邻节点间的边 ...

  7. 字典树 Trie树

    什么是Trie树? 形如 其中从根节点到红色节点的路径上的字母所连成的字符串即为一个Trie树上所存的字符串. 比如,这个trie树上有ab,abc,bd,dda这些字符串. 至于怎么构建和查找或添加 ...

  8. 【HDU - 5790 】Prefix(主席树+Trie树)

    BUPT2017 wintertraining(15) #7C 题意 求[min((Z+L)%N,(Z+R)%N)+1,max((Z+L)%N,(Z+R)%N)+1]中不同前缀的个数,Z是上次询问的结 ...

  9. Luogu P2922 [USACO08DEC]秘密消息Secret Message 字典树 Trie树

    本来想找\(01Trie\)的结果找到了一堆字典树水题...算了算了当水个提交量好了. 直接插入模式串,维护一个\(Trie\)树的子树\(sum\)大小,求解每一个文本串匹配时走过的链上匹配数和终点 ...

随机推荐

  1. python笔记7:优雅的python

    7. 如何让python代码更 Pythonic : 1.变量交换: a, b = b, a 2.带有索引位置的集合遍历: colors = ['red', 'green', 'blue', 'yel ...

  2. HDU 1020 Encoding【连续的计数器重置】

    Encoding Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  3. 分享Kali Linux 2017.1镜像

     分享Kali Linux 2017.1镜像 Kali Linux官方于4月24日发布Kali Linux 2017.1版本.该版本仍然采用滚动更新方式,所以软件源为kali-rolling.至现在分 ...

  4. 基于Java实现的选择排序算法

    选择排序和冒泡排序同样是基础排序算法,现在也做个学习积累. 简述 选择排序算法较为稳定,基本上都是O(n2)的时间复杂度,规模越小排序越快,不需要占用额外空间.其实选择排序原理很简单,就是在未排序序列 ...

  5. Jackson是线程安全的吗

    网上说是线程安全的,内部代码用了ThreadLocal.Synchronized这些线程安全类和关键字,可以放心的用. 避免每次使用都new一个,全局配置一个ObjectManager的对象将大大减少 ...

  6. hdu1708(C++)

    这个题目明确说了不涉及大数,假设第i个为b[i]: b[0]=s1; b[1]=s2; b[3]=s1+s2; b[4]=s1+2*s2; b[5]=2*s1+3*s2: b[6]=3*s1+5*s2 ...

  7. 15 THINGS ALL GIRLS SHOULD KNOW ABOUT THEIR VAGINA

    Here are 15 facts that EVERY GIRL should know about her vagina. Don’t be shy! Your vagina is part of ...

  8. 【重点突破】—— Vue1.0到Vue2.0的变化

    前言: 本文参考作者:_So_ 和 我是某慧 的博文,重点梳理Vue1.0升级到Vue2.0后在开发中要注意的不同,以做学习.        组件模板不再支持片段代码,必须有一个顶级元素包裹,例如: ...

  9. 2017.2.7 开涛shiro教程-第六章-Realm及相关对象(一)

    原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第六章 Realm及相关对象 1.用户.角色.权限的关系 用户和角 ...

  10. C++的标准模板库STL中实现的数据结构之顺序表vector的分析与使用

    摘要 本文主要借助对C++的标准模板库STL中实现的数据结构的学习和使用来加深对数据结构的理解.即联系数据结构的理论分析和详细的应用实现(STL),本文是系列总结的第一篇,主要针对线性表中的顺序表(动 ...