[题解]bzoj3600 没有人的算数
2017-07-11 10:40
573 查看
Solution
就是线段树,最麻烦的地方就是比较两个数的大小。我们可以想到给每个数映射到一个double值,但是double的精度有限,如果数太多就会挂掉。所以我们可以用平衡树维护。但是插入的时候还是有比较大小的问题。
注意到新数由原来的数生成,所以原来的数在平衡树中的大小可以用来进行比较。我们可以把每一个平衡树中的节点对应区间(l,r),然后他的左孩子对应(l,mid)
,右孩子对应(mid,r),每个节点的权值为mid,这样就在
4000
精度有限的情况下(因为平衡树不会太高),把数对映射到了平衡树中。为了维护每个节点的l、r,我们不能用带旋转的平衡树,所以考虑用替罪羊或者Treap。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=500010; int n,m,mx[maxn<<2],pos[maxn]; double val[maxn]; template<typename T>inline void read(T &x){ T f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0'; x*=f; } struct Data{ int fir,sec; bool operator<(Data b){ if(val[fir]==val[b.fir])return val[sec]<val[b.sec]; return val[fir]<val[b.fir]; } bool operator==(Data b){ if(val[fir]!=val[b.fir]||val[sec]!=val[b.sec])return false; return true; } }; struct ScapeGoat{ int id,A[maxn<<1],top,sum,root; double idll,idrr; int size[maxn<<1],ch[maxn<<1][2],fa[maxn<<1]; Data a[maxn<<1]; ScapeGoat(){ id=top=sum=root=0; memset(size,0,sizeof size); memset(ch,0,sizeof ch); memset(a,0,sizeof a); memset(fa,0,sizeof fa); } bool Bad(int x){ return max(size[ch[x][0]],size[ch[x][1]])>0.75*size[x]+4; } int Build(int f,int l,int r,double ll,double rr){ if(l>r)return 0; int mid=(l+r)>>1,x=A[mid]; double mv=(ll+rr)/2.0; fa[x]=f;val[x]=mv; ch[x][0]=Build(x,l,mid-1,ll,mv); ch[x][1]=Build(x,mid+1,r,mv,rr); size[x]=size[ch[x][0]]+size[ch[x][1]]+1; return x; } void Dfs(int x){ if(!x)return; Dfs(ch[x][0]);ch[x][0]=0; A[++top]=x; Dfs(ch[x][1]);ch[x][1]=0; } void ReBuild(int x,double ll,double rr){ top=0;Dfs(x); int p=(x==ch[fa[x]][1]); if(fa[x])ch[fa[x]][p]=Build(fa[x],1,top,ll,rr); else root=Build(0,1,top,ll,rr); } int Insert(int &x,int f,double ll,double rr,Data v){ double mv=(ll+rr)/2.0; if(!x){ val[x=++sum]=mv;a[x]=v; size[x]=1;fa[x]=f; return x; } int p; if(v==a[x])return x; else{ size[x]++; if(a[x]<v)p=Insert(ch[x][1],x,mv,rr,v); else p=Insert(ch[x][0],x,ll,mv,v); } if(Bad(x))id=x,idll=ll,idrr=rr; return p; } }sg; void Modify(int x,int l,int r,int p){ if(l==r)return mx[x]=l,void(); int mid=(l+r)>>1; if(p<=mid)Modify(x<<1,l,mid,p); else Modify(x<<1|1,mid+1,r,p); int a=mx[x<<1],b=mx[x<<1|1]; if(val[pos[a]]>=val[pos[b]])mx[x]=a; else mx[x]=b; } int Query(int x,int l,int r,int ql,int qr){ if(l>=ql&&r<=qr)return mx[x]; int mid=(l+r)>>1; int p=0,ans=0; if(ql<=mid)ans=Query(x<<1,l,mid,ql,qr); if(qr>mid){ p=Query(x<<1|1,mid+1,r,ql,qr); if(!ans)ans=p; else if(val[pos[ans]]<val[pos[p]])ans=p; } return ans; } int main(){ read(n);read(m); sg.Insert(sg.root,0,0,1,Data{0,0}); for(int i=1;i<=n;i++)pos[i]=1; for(int i=1;i<=n;i++)Modify(1,1,n,i); while(m--){ char opt[10]; int l,r,k; scanf("%s",opt);read(l);read(r); if(opt[0]=='C'){ read(k);sg.id=0; pos[k]=sg.Insert(sg.root,0,0,1,Data{pos[l],pos[r]}); if(sg.id)sg.ReBuild(sg.id,sg.idll,sg.idrr); Modify(1,1,n,k); } else printf("%d\n",Query(1,1,n,l,r)); } return 0; }
相关文章推荐
- [题解]bzoj3600 没有人的算数
- 【题解】BZOJ 3600: 没有人的算术——替罪羊树、线段树
- 【替罪羊树-动态标号+线段树】BZOJ3600[没有人的算术]题解
- [bzoj3600]没有人的算术 替罪羊树+线段树
- bzoj 3600 没有人的算术 - 替罪羊树 - 线段树
- 【bzoj3600】没有人的算术
- BZOJ 3600 没有人的算术
- bzoj 3600 - 没有人的算术
- bzoj3600 没有人的算术
- [替罪羊树 动态标号 线段树] BZOJ 3600 没有人的算术
- [bzoj3600]没有人的算术
- [bzoj3600]没有人的算术
- [BZOJ3600][线段树][替罪羊树]没有人的算术
- [BZOJ3600][没有人的算术][替罪羊树+线段树]
- bzoj 3600: 没有人的算术 (替罪羊树)
- bzoj 3600: 没有人的算术 替罪羊树+线段树
- bzoj 3600: 没有人的算术 替罪羊树
- bzoj 3600: 没有人的算术
- [BZOJ3600]没有人的算术 重量平衡树+线段树
- 3600: 没有人的算术