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; }