由运算符有优先级可以想到先算优先级小的,然后两边递归,但符号比较少,有大量相同的,同级之间怎么办呢?因为运算符满足结合律,同级之间选一个然后两边递归也是没问题的,然后我们想到用fhqtreap进行维护,但堆那一维不是随机的,所以我们merge时再按两棵树的大小比例搞一个随机,把小的往大的上合(玄学,如果直接把小的和到大的上得30分),另外说一下是满足交换律才能用这种方法的,要不满足交换律转一下值就全换了,还要遍历整棵树来维护。
注意merge(l,r)应保证r里的元素的二叉排序树那一维的劝值大于l。
第一次写这种数据结构,直接抄的题解
PS:代码来源:http://blog.csdn.net/werkeytom_ftd/article/details/50635596;
#include "expr.h" #include<ctime> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int maxn=30000000+10; int root[maxn],siz[maxn],tr[maxn][2],fix[maxn]; bool bz[maxn]; Data key[maxn],num[maxn],wdc; int i,j,k,l,mid,r,n,m,tot,top; int newno(int x){ siz[++tot]=siz[x];tr[tot][0]=tr[x][0];tr[tot][1]=tr[x][1]; fix[tot]=fix[x];bz[tot]=bz[x];key[tot]=key[x];num[tot]=num[x]; return tot; } void update(int x){ siz[x]=siz[tr[x][0]]+siz[tr[x][1]]+1; if(fix[x]<=100&&tr[x][0]&&tr[x][1]) num[x]=F(num[tr[x][0]],num[tr[x][1]],fix[x]); else num[x]=key[x]; } void mark(int &x){ if(!x)return; int y=newno(x); bz[y]^=1;swap(tr[y][0],tr[y][1]); x=y; } void pushdown(int x){ if(bz[x]){mark(tr[x][0]);mark(tr[x][1]);bz[x]=0;} } bool cmp(int x,int y){ if(fix[x]==fix[y])return ((siz[y])<siz[x]); else return fix[x]<fix[y]; } void merge(int l,int r,int &x){ if(!l||!r){x=l+r;return;} pushdown(l);pushdown(r); int t; if(cmp(l,r)){ t=newno(l); merge(tr[l][1],r,tr[t][1]); } else{ t=newno(r); merge(l,tr[r][0],tr[t][0]); } update(t); x=t; } void split(int x,int y,int &l,int &r){ if(!x){l=r=0;return;} if(!y){l=0;r=x;return;} pushdown(x); int t; if(siz[tr[x][0]]>=y){ split(tr[x][0],y,l,r); t=newno(x);tr[t][0]=r; update(t);r=t; } else{ split(tr[x][1],y-siz[tr[x][0]]-1,l,r); t=newno(x);tr[t][1]=l; update(t);l=t; } } void init(int test_id,int n,int m,int k,const Data *a,const int *ops){ srand(time(0)); wdc=a[0];top=0;int t; for(int i=n;i>=1;--i){ t=newno(0);siz[t]=1;fix[t]=101; key[t]=num[t]=a[i-1]; merge(t,root[0],root[0]); if(i>1){ int t=newno(0); siz[t]=1;fix[t]=ops[i-1];key[t]=num[t]=wdc; merge(t,root[0],root[0]); } } } Data modify_data(int id,int pos,Data x){ ++top;++pos; split(root[id],2*pos-1,l,r); split(l,2*pos-2,l,mid); int t=newno(mid); key[t]=num[t]=x; merge(l,t,l);merge(l,r,root[top]); return num[root[top]]; } Data modify_op(int id,int pos,int new_op){ ++top; split(root[id],2*pos,l,r); split(l,2*pos-1,l,mid); int t=newno(mid); fix[t]=new_op; merge(l,t,l);merge(l,r,root[top]); return num[root[top]]; } Data reverse(int id,int l,int r){ ++top; ++l,++r;j=l;k=r; split(root[id],2*k-1,l,r); split(l,2*j-2,l,mid); mark(mid); merge(l,mid,l); merge(l,r,root[top]); return num[root[top]]; }