郁闷的小 J------NB树
MoCaRabbit · · 题解
虽然此题有更好的做法,但是我就是那个 S*。
因为本人过于 stupid,写此题是还不会按值域去干嘛干嘛的。
所以写下了这份线段树维护区间,平衡树维护区间内的数的代码。
先说一下这样与分析时间复杂度。
线段树会将一个区间分为
将那些区间的编号为
你问我为什么不能用哈希表,因为就是那个 S*。因为我写的 Hash 如果模数小,那么会爆时间,模数大,数组大,会爆空间。
还不如指针平衡树。
先给份 treap 的代码。
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[100010];
struct node{
node *l,*r;
int val,cnt,siz;
};
struct tree{
node *root,*null;
inline tree(){
null=new node;
null->l=null->r=null;
null->val=null->cnt=null->siz=0;
root=null;
}
inline void update(node *p){
p->siz=p->l->siz+p->r->siz+p->cnt;
}
inline void zig(node *&p){
node *q=p->l;
if(q==null) return;
p->l=q->r,q->r=p,p=q;
update(p->r),update(p);
}
inline void zag(node *&p){
node *q=p->r;
if(q==null) return;
p->r=q->l,q->l=p,p=q;
update(p->l),update(p);
}
inline int check(node *p){
if(p->r->siz*0.6>=double(p->l->siz)) return 1;
if(p->l->siz*0.6>=double(p->r->siz)) return 2;
return 0;
}
void insert(int x,node *&p){
if(p==null){
p=new node;
p->l=p->r=null;
p->val=x;
p->cnt=1;
p->siz=1;
return;
}
if(x==p->val) p->cnt++;
else if(x<p->val) insert(x,p->l);
else insert(x,p->r);
update(p);
int d=check(p);
if(d==1) zag(p);
if(d==2) zig(p);
}
void erase(int val,node *&p){
if(p==null) return;
if(val==p->val){
if(p->cnt>1){
p->cnt--,update(p);
return;
}
if(p->l!=null || p->r!=null){
if(p->r==null)
zig(p),erase(val,p->r);
else
zag(p),erase(val,p->l);
update(p);
}
else p=null;
return;
}
if(val<p->val) erase(val,p->l);
else erase(val,p->r);
int d=check(p);
if(d==1) zag(p);
if(d==2) zig(p);
update(p);
}
int count(int x,node *p){
if(p==null) return 0;
if(p->val==x) return p->cnt;
if(x<p->val) return count(x,p->l);
else return count(x,p->r);
}
}t[400010];
inline void creat(int l,int r,int root){
t[root]=tree();
if(l==r){
t[root].insert(a[l],t[root].root);
return;
}
int mid=l+r>>1;
creat(l,mid,root*2);
creat(mid+1,r,root*2+1);
for(int i=l;i<=r;i++) t[root].insert(a[i],t[root].root);
}
inline int update(int p,int k,int x=1,int y=n,int root=1){
if(x==y && p==x){
int u=t[root].root->val;
t[root].root->val=k;
return u;
}
int mid=x+y>>1,tot=0;
if(p<=mid) tot=update(p,k,x,mid,root*2);
else tot=update(p,k,mid+1,y,root*2+1);
t[root].erase(tot,t[root].root);
t[root].insert(k,t[root].root);
return tot;
}
inline int ask(int l,int r,int k,int x=1,int y=n,int root=1){
if(l<=x && y<=r) return t[root].count(k,t[root].root);
int mid=x+y>>1,tot=0;
if(l<=mid) tot+=ask(l,r,k,x,mid,root*2);
if(mid<r) tot+=ask(l,r,k,mid+1,y,root*2+1);
return tot;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
inline char chread(){
char ch=getchar();
while(!isalpha(ch)) ch=getchar();
return ch;
}
inline void write(int x){
if(x<10){
putchar(x%10+'0');
return;
}
write(x/10);
putchar(x%10+'0');
}
int main() {
srand(time(0));
cin>>n>>m;
for(int i=1;i<=n;i++) a[i]=read();
creat(1,n,1);
char ch;
int l,r;
while(m--){
ch=chread();
l=read(),r=read();
if(ch=='C') update(l,r),a[l]=r;
if(ch=='Q'){
int k;
cin>>k;
write(ask(l,r,k));
putchar('\n');
}
}
return 0;
}
空间
忽略常数,在
因为树套树常数位两树之积,因为这两位都是大常数选手,所以直接爆炸。
在这种情况下,你知道 treap 靠什么吗?
天,赐,良,机!
机,主要指随机数,次要指评测机。
然后这份代码再也 A 不掉了。
换上替罪羊树,我们继续作战。
虽然替罪羊是个基于暴力的树。
但是常数比我写的很多树都小。
先试下
没事,
所以说,平衡树的一些参数对时间很重要。
这是我写的 treap。
这是我写的替罪羊树。