【LG P3369】郁闷的小J
一开始只当成是练一下\(\mathrm{Treap}\)(毕竟大半年没碰过键盘了),没想到真的写出来了
首先排除建100000棵线段树的幼稚设想
修改操作可能有点魔幻,不妨先考虑如何维护查询操作
因为每次只查询一种编号的书,其他操作跟线段树没什么区别
所以有了一个大胆的设想:\(\mathrm{Treap}\)当中的元素可以换成双关键字
具体来说,就是将书的编号作为第一关键字,书的位置作为第二关键字
这样,同一编号的书在\(\mathrm{Treap}\)当中就是连续的,就可以查询特定区间内有多少个节点了
再细想的话,修改本身也不难
因为每次只替换一本书,而且很显然,每本书在\(\mathrm{Treap}\)中的两个关键字不可能完全相同
所以,可以在一开始读入时,可以直接开一个双关键字数组,把每个位置书的编号用结构体记下来
如果要替换掉某个位置的书,就用\(\mathrm{Treap}\)模板中的delete
函数,再用前款当中的那个数组调出这个位置的书的数据,delete
即可,然后再insert
一次即可
注意事项:
- 因为
delete
一遍之后,\(\mathrm{Treap}\)当中的*now
不会倒回去(醒醒,这不是动态开点!),所以极限情况下,该题的数据范围应该开到2e5
,然后我傻乎乎地以为delete
可以减少内存,炸了半小时 - 统计区间内编号个数时,要把
lower_bound
和upper_bound
写清楚 - 结构体套结构体的时候,少用
non-static
的预定义 - 把结构体的自定义运算符写好
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<climits>
const int maxn=2e5+5;
struct Book
{
int idx,pos;
bool operator < (const Book &x) const{return ( idx!=x.idx ? idx<x.idx : pos<x.pos );}
bool operator > (const Book &x) const{return ( idx!=x.idx ? idx>x.idx : pos>x.pos );}
bool operator == (const Book &x) const{return ( idx==x.idx and pos==x.pos );}
bool operator >= (const Book &x) const{return ( idx!=x.idx ? idx>x.idx : pos>=x.pos );}
};
struct BT
{
struct Node
{
Book v;
int idx,sz;
Node* son[2];
void update()
{
sz=1;
if( son[0] ) sz+=son[0]->sz;
if( son[1] ) sz+=son[1]->sz;return;
}
}Tree[maxn],*now=Tree;
void rotate(Node* &r,int d)
{
Node* tmp=r->son[d^1];
r->son[d^1]=r->son[d^1]->son[d],tmp->son[d]=r;
r->update();
r=tmp,tmp->update();return;
}
void insert(Node* &r,Book v)
{
if(!r)
{
r=now++;
r->v=v,r->idx=rand(),r->son[0]=r->son[1]=NULL,r->sz=1;return;
}
int d=( v>r->v );
insert(r->son[d],v);
r->update();
if( r->idx > r->son[d]->idx ) rotate(r,d^1);
}
void del(Node* &r,Book v)
{
if(!r) return;
if( r->v==v )
{
if( !r->son[0] and !r->son[1] ) r=NULL;
else if( !r->son[0] xor !r->son[1] )
{
int d=(r->son[1]!=NULL);
r=r->son[d];
}
else
{
int d=( r->son[0]->idx < r->son[1]->idx );
rotate(r,d),del(r->son[d],v);
r->update();
}return;
}
int d=( v>r->v );
del(r->son[d],v),r->update();
}
int num_lower_search(Node* r,Book v)
{
if(!r) return 0;
if( v>r->v ) return ( (r->son[0]!=NULL)?r->son[0]->sz:0 ) + 1 + num_lower_search(r->son[1],v);
else return num_lower_search(r->son[0],v);
}
int num_upper_search(Node* r,Book v)
{
if(!r) return 0;
if( v>=r->v ) return ( (r->son[0]!=NULL)?r->son[0]->sz:0 ) + 1 + num_upper_search(r->son[1],v);
else return num_upper_search(r->son[0],v);
}
}bt;
Book a[maxn];
int main()
{
srand(time(0));
BT::Node* root=NULL;
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
a[i].pos=i,scanf("%d",&a[i].idx);
bt.insert(root,a[i]);
}
while(m--)
{
char op;scanf(" %c",&op);
if( op=='C' )
{
int p,id;scanf("%d%d",&p,&id);
bt.del(root,a[p]);
a[p].idx=id;
bt.insert(root,a[p]);
}
else
{
int l,r,id;scanf("%d%d%d",&l,&r,&id);
Book L=(Book){id,l},R=(Book){id,r};
printf("%d\n",bt.num_upper_search(root,R)-bt.num_lower_search(root,L));
}
}
return 0;
}