您的位置:首页 > 其它

bzoj3600: 没有人的算术

2017-11-15 19:09 169 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=3600

题意大概是维护一个由二叉树组成的序列a,初始每个位置为单个点的树,支持单点修改(把a[l]和a[r]分别作为根的左右子树,放在a[x]),查询区间最大值(按先序遍历字典序比较,空<非空)的位置。

用动态标号法维护一下当前已出现过的所有二叉树的大小顺序,线段树支持区间查询。

#include<bits/stdc++.h>
typedef long long i64;
const int P=1844677,MX=1<<30;
char ib[10000007],*ip=ib;
int _(){
int x=0;
while(*ip<48)++ip;
while(*ip>47)x=x*10+*ip++-48;
return x;
}
int n,m,tr[277777],a[133333],mx,idp=0;
struct node{
node*c[2];
int rnd,M,ls,rs;
void rb(int L,int R){
if(!this)return;
M=L+R;
c[0]->rb(L,M>>1);
c[1]->rb(M>>1,R);
}
}ns[500007],*np=ns,*rt;
bool cmp(int a,int b){return ns[a].M<ns[b].M;}
void up(int&w,int l,int r){w=cmp(a[l],a[r])?r:l;}
bool cmp(node*a,node*b){return a==ns||(a->ls!=b->ls?cmp(a->ls,b->ls):cmp(a->rs,b->rs));}
int h[P][4];
#define $(a,b,c) (*a=b,a=&c,b=*a)
void ins(int x,int ls,int rs){
node**w=&rt;
*np=(node){0,0,rand(),0,ls,rs};
int L=0,R=MX;
for(;;){
node*a=*w;
if(!a||np->rnd>a->rnd){
*w=np;
np->M=L+R;
node**l=np->c,**r=l+1;
while(a)cmp(a,np)?$(l,a,a->c[1]):$(r,a,a->c[0]);
*l=*r=0;
return np++->rb(L,R);
}
int d=cmp(a,np);
w=a->c+d;
(d?L:R)=(L+R)>>1;
}
}
int getid(int a,int b){
int w=(a*149+b*293)%P;
while(h[w][0]){
if(h[w][1]==a&&h[w][2]==b)return h[w][3];
w=(w+13999)%P;
}
h[w][0]=1;
h[w][1]=a;
h[w][2]=b;
h[w][3]=++idp;
ins(idp,a,b);
return idp;
}
int main(){
fread(ib,1,sizeof(ib),stdin);
n=_();m=_();
srand(n+m+131);
for(mx=2;mx<=n+2;mx<<=1);
for(int i=1;i<=n;++i)tr[mx+i]=i;
for(int i=mx-1;i;--i)tr[i]=tr[i*2];
ins(0,-1,-1);
while(m--){
int o=_(),l=_(),r=_();
if(o+48=='C'){
int x=_();
a[x]=getid(a[l],a[r]);
for(int w=mx+x>>1;w;w>>=1)up(tr[w],tr[w*2],tr[w*2+1]);
}else{
int ml=l,mr=r;
for(l+=mx,r+=mx;r-l>1;l>>=1,r>>=1){
if(~l&1)up(ml,ml,tr[l+1]);
if(r&1)up(mr,tr[r-1],mr);
}
up(ml,ml,mr);
printf("%d\n",ml);
}
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: