【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 安装cx_Oracle模块, MySQLdb模块, Tornado

    一,想访问远程Oracle数据库,本地又不想安装几百兆的Oracle Client(也木有root权限),安装python的cx_Oralce 模块需要依赖Oracle Instant Client ...

  2. 大型网站优化-memcache技术

    大型网站优化-memcache技术 memory+cache 内存缓存 memcache简介 memcache是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发 ...

  3. SpringBoot 分包方式多数据源

    1.引入依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spri ...

  4. Copy Records From One Data Block To Another Data Block In Oracle Forms

    In this tutorial you will learn to copy the records from one data block to another data block on sam ...

  5. flask的httponly默认值为True

    如图flask的app.py里显示app的默认配置,httponly默认值为true,所以如果开发者不修改这个配置的话,攻击者是无法通过xss攻击读取浏览器cookie这部分信息的. Cookie:s ...

  6. 传输层:UDP 协议

    一.传输层协议 从之前介绍的网络层协议来看,通信的两端是两台主机,IP 数据报首部就标明了这两台主机的 IP 地址.但是从传输层来看,是发送方主机中的一个进程与接收方主机中的一个进程在交换数据,因此, ...

  7. CSS实现鼠标放图片上显示白色边框+文字描写叙述

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. netty实现长连接心跳检

    主要逻辑: 使用netty实现长连接,主要靠心跳来维持服务器端及客户端连接. 实现的逻辑主要是: 服务器端方面: 1, 服务器在网络空闲操作一定时间后,服务端失败心跳计数器加1. 2, 如果收到客户端 ...

  9. GUID概念

     GUID概念 GUID: 即Globally Unique Identifier(全球唯一标识符) 也称作 UUID(Universally Unique IDentifier) . GUID是 ...

  10. UNP学习笔记(第七章 套接字选项)

    有多种方法获取和设置影响套接字的选项: 1.getsockopt和setsockopt函数 2.fcntl函数 3.ioctl函数 getsockopt和setsockopt函数 这两个函数仅用于套接 ...