题意:

【BZOJ3600】没有人的算术 - 替罪羊树+线段树-LMLPHP

【BZOJ3600】没有人的算术 - 替罪羊树+线段树-LMLPHP

【BZOJ3600】没有人的算术 - 替罪羊树+线段树-LMLPHP

题解:

Orz vfleaking……真·神题

做法大概是先把题意中定义的“数”都赋一个实数权值,用平衡树来维护整个从大到小排序过的序列,再用线段树查询最值;

这样做为什么是对的?考虑插入一个数$x$,我们已经知道了$x_L$和$x_R$在序列中的位置,就可以直接每次$O(1)$比较权值大小来找到$x$应该插入的位置,这样子单次插入是$O(logn)$的;

再考虑赋值,可以把根节点的区间设为$(0,1)$,然后每个点的权值都赋为这个区间中点的值,向子树递归赋值即可;由于平衡树树高是$O(logn)$的,最小精度限制就是$2^{-logn}=\frac{1}{n}$的,可以直接用double存;但是一个问题是普通的平衡树在旋转之后整棵子树的权值都需要重新计算,因此就要用不需要旋转的重量平衡树,这里我用的替罪羊树;

ps:貌似我写的替罪羊是假的……rebuild的地方会重复rec很多次……alpha小了会T,大了会WA……经过面对oj调参+玄学读优才卡时限过……

代码:

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 1000000007
#define eps 1e-9
using namespace std;
typedef long long ll;
typedef double db;
const db alpha=0.865;
int n,m,l,r,k,rt=,cur,cnt=,top=,nw[],st[];
db s[];
char op[];
struct num{
int x,y;
num(){}
num(int _x,int _y){
x=_x,y=_y;
}
friend bool operator ==(num a,num b){
return a.x==b.x&&a.y==b.y;
}
friend bool operator <(num a,num b){
return a.x==b.x?s[a.y]<s[b.y]:s[a.x]<s[b.x];
}
};
struct node{
int ls,rs,siz;
//db s;
num v;
}t[];
struct _node{
int v,p;
}tr[];
char buffer[],*hd,*tl;
inline char Getchar(){
if(hd==tl){
int len=fread(buffer,,,stdin);
hd=buffer,tl=hd+len;
if(hd==tl)
return EOF;
}
return *hd++;
}
inline int rd(){
register int x=,f=;
char c;
do{
c=Getchar();
if(c=='-')f=-;
}while(!isdigit(c));
do{
x=(x<<)+(x<<)+(c^);
c=Getchar();
}while(isdigit(c));
return x*f;
}
void getmx(num &a,num b){
if((a.y==b.y&&a.x>b.x)||s[a.y]<s[b.y])a=b;
}
bool ndrb(int u){
return t[t[u].ls].siz>t[u].siz*alpha+||t[t[u].rs].siz>t[u].siz*alpha+;
}
void rec(int u){
if(t[u].ls)rec(t[u].ls);
st[++top]=u;
if(t[u].rs)rec(t[u].rs);
}
void rebuild(int &u,int l,int r,db L,db R){
int mid=(l+r)/;
db Mid=(L+R)/;
u=st[mid];
s[u]=Mid;
t[u].ls=t[u].rs=;
if(l<mid)rebuild(t[u].ls,l,mid-,L,Mid);
if(mid<r)rebuild(t[u].rs,mid+,r,Mid,R);
t[u].siz=t[t[u].ls].siz+t[t[u].rs].siz;
}
void rb(int &u,db L,db R){
top=;
rec(u);
rebuild(u,,top,L,R);
}
int ins(int &u,db L,db R,num x){
db Mid=(L+R)/;
if(!u){
u=++cnt;
t[u].v=x;
s[u]=Mid;
t[u].ls=t[u].rs=;
t[u].siz=;
return u;
}
t[u].siz++;
if(ndrb(u))rb(u,L,R);
if(x==t[u].v)return u;
else if(x<t[u].v)return ins(t[u].ls,L,Mid,x);
else return ins(t[u].rs,Mid,R,x);
}
void pushup(int u){
if(tr[u*].v==tr[u*+].v||s[tr[u*].v]>s[tr[u*+].v]){
tr[u].v=tr[u*].v;
tr[u].p=tr[u*].p;
}else{
tr[u].v=tr[u*+].v;
tr[u].p=tr[u*+].p;
}
}
void build(int l,int r,int u){
tr[u].v=;
tr[u].p=l;
if(l==r)return;
int mid=(l+r)/;
build(l,mid,u*);
build(mid+,r,u*+);
}
void updata(int l,int r,int u,int p){
if(l==r){
tr[u].v=nw[l];
tr[u].p=l;
return;
}
int mid=(l+r)/;
if(p<=mid)updata(l,mid,u*,p);
else updata(mid+,r,u*+,p);
pushup(u);
}
num query(int l,int r,int u,int L,int R){
if(L<=l&&r<=R){
return num(tr[u].p,tr[u].v);
}
int mid=(l+r)/;
num ret(,);
if(L<=mid)getmx(ret,query(l,mid,u*,L,R));
if(mid<R)getmx(ret,query(mid+,r,u*+,L,R));
return ret;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("10.in","r",stdin);
freopen("my.out","w",stdout);
#endif
//scanf("%d%d",&n,&m);
n=rd(),m=rd();
cur=ins(rt,,,num(,));
for(int i=;i<=n;i++)nw[i]=cur;
build(,n,);
for(int i=;i<=m;i++){
//scanf("%s%d%d",op,&l,&r);
char ch;
ch=Getchar();
while(ch!='C'&&ch!='Q')ch=Getchar();
l=rd(),r=rd();
if(ch=='C'){
//scanf("%d",&k);
k=rd();
nw[k]=ins(rt,,,num(nw[l],nw[r]));
updata(,n,,k);
}else printf("%d\n",query(,n,,l,r).x);
}
return ;
}
05-11 18:14