当前位置: 代码迷 >> 综合 >> bzoj 3600: 没有人的算术 (替罪羊树)
  详细解决方案

bzoj 3600: 没有人的算术 (替罪羊树)

热度:75   发布时间:2023-09-30 17:26:57.0


为什么我没有copy题面呢?看到题面你就懂了....hh


题意:

定义一个二元组(二元组的两个元素可以是二元组)

如(x,y),其中x可以是(a,(b,c))之类的

定义二元组的比较方式:先比较左边,左边相同再比较右边。

递归比较可以用随便哪颗平衡树维护,70分


考虑对于每个 二元组,对他定义一个实数的映射来表示它的大小,想象我们在将它插入平衡树时,一路比较,按照比较结果判断是插入左子树还是右子树,那实际上它最终的位置就是他的映射,70分做法即为如此,缺陷在于比较是log的,可是,我们既然已经知道他所在最终位置(映射出的实数),且映射的大小关系等价于它本身的大小关系,那为何不用映射出的实数去构造新的二元组呢?这样比较就变成O(1)的了。

可是,映射显然只是一种相对的位置关系,常用的平衡树均有旋转操作,那就意味着映射大小改变,将不断的重新计算映射,得不偿失。可是,非旋转treap和替罪羊树并无旋转操作啊!


代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<climits>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define N 500020
using namespace std;
inline int read()
{int x=0,f=1;char ch;while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
int n,m;
double a[N];
int ts[N],tot;
int R,rt,pos[N],mx[N];
struct data
{int l,r;friend bool operator < (data x,data y){if(a[x.l]<a[y.l])return 1;if(a[x.l]==a[y.l]&&a[x.r]<a[y.r])return 1;return 0;}	friend bool operator == (data x,data y){if(a[x.l]!=a[y.l]||a[x.r]!=a[y.r])return 0;return 1;}
};
struct sctree
{int cnt,size[N],ls[N],rs[N];data v[N];void dfs(int k){if(!k)return ;dfs(ls[k]);ts[++tot]=k;dfs(rs[k]);}void build(int &u,int l,int r,double lv,double rv){if(l>r){u=0;return;}double mv=(lv+rv)/2.0;int mid=(l+r)>>1;u=ts[mid];a[u]=mv;build(ls[u],l,mid-1,lv,mv);build(rs[u],mid+1,r,mv,rv);size[u]=size[ls[u]]+size[rs[u]]+1;}void rebuild(int &u,double lv,double rv){tot=0;dfs(u);build(u,1,tot,lv,rv);}int insert(int &u,double lv,double rv,data val){double mv=(lv+rv)/2.0;if(!u){u=++cnt;v[u]=val;a[u]=mv;size[u]=1;return u;}int p;if(val==v[u])return u;else{size[u]++;if(val<v[u])p=insert(ls[u],lv,mv,val);else p=insert(rs[u],mv,rv,val);}if(size[u]*0.75>max(size[ls[u]],size[rs[u]])){if(R){if(ls[u]==R)rebuild(ls[u],lv,mv);else rebuild(rs[u],mv,rv);R=0;}}else R=u;return p;}
}sc;
void add(int u,int l,int r,int v)
{if(l==r){mx[u]=v;return;}int mid=(l+r)>>1;if(v<=mid)add(u<<1,l,mid,v);else add(u<<1|1,mid+1,r,v);int x=mx[u<<1],y=mx[u<<1|1];if(a[pos[x]]<a[pos[y]])mx[u]=y;else mx[u]=x;
}int query(int u,int l,int r,int x,int y)
{if(x==l&&y==r)return mx[u];int mid=(l+r)>>1;int ret=0;if(y<=mid)return query(u<<1,l,mid,x,y);else if(x>mid)return query(u<<1|1,mid+1,r,x,y);else{int s=query(u<<1,l,mid,x,mid);int t=query(u<<1|1,mid+1,r,mid+1,y);if(a[pos[s]]>a[pos[ret]])ret=s;if(a[pos[t]]>a[pos[ret]])ret=t;}return ret;
}
int main()
{n=read(),m=read();char ch[10];a[0]=-1;sc.insert(rt,0,1,(data){0,0});for(int i=1;i<=n;i++)pos[i]=1;for(int i=1;i<=n;i++)add(1,1,n,i);for(int i=1;i<=m;i++){scanf("%s",ch);int l=read(),r=read();if(ch[0]=='C'){int k=read();pos[k]=sc.insert(rt,0,1,(data){pos[l],pos[r]});if(R)sc.rebuild(rt,0,1);R=0;add(1,1,n,k);}else printf("%d\n",query(1,1,n,l,r));}
}



























  相关解决方案