替罪羊树

通过子树大小和树大小的关系进行重构,复杂度均摊logn。

 

bzoj3600 没有人的算术

题目大意:一开始只有0,每次可以把两个数x,y组成(x,y)的形式作为新数,数(a,b)(x,y)的比较以第一维为第一关键字、第二维为第二关键字。操作有:把l和r上的数组成新数赋给k,求[l,r]中最大数的下标(数相同时取小下标)。

思路:考虑如果维护数的信息,可以用重量平衡树,用替罪羊树,对每个数维护一个vi,vi表示平衡树上区间的中点(rt的区间是[0,1],左子树的是[l,mid],右子树的是[mid,r]),插入的时候找到深度最浅的那个点暴力重构。查询就是在线段树上查区间最值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 500005
#define alp 0.75
#define LD double
#define eps 1e-9
using namespace std;
char chin(){
    char ch=getchar();
    while(ch!='C'&&ch!='Q') ch=getchar();
    return ch;}
int in(){
    char ch=getchar();int x=0;
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';ch=getchar();
    }return x;}
int cmp(LD x,LD y){
    if (x-y>eps) return 1;
    if (y-x>eps) return -1;
    return 0;}
struct tree{int mx,mp;}tr[N<<2];
LD vi[M];
struct point{
    int x,y;
    bool operator==(const point&xx)const{return x==xx.x&&y==xx.y;}
    bool operator<(const point&xx)const{
        return (cmp(vi[x],vi[xx.x])==0 ? cmp(vi[y],vi[xx.y])<0 : cmp(vi[x],vi[xx.x])<0);}
}bi[M];
struct use{
    int l,r,sz,po;LD le,re;
    bool operator<(const use&x)const{return bi[po]<bi[x.po];}
}tp[M],zh[M];
int ai[N],rt,tt=0,bz=0,uf,zt,id[M],iz;
tree updata(tree x,tree y){
    tree c;
    if (cmp(vi[x.mx],vi[y.mx])>=0){
        c.mx=x.mx;c.mp=x.mp;
    }else{c.mx=y.mx;c.mp=y.mp;}
    return c;}
void build(int i,int l,int r){
    if (l==r){tr[i]=(tree){ai[l],l};return;}
    int mid=(l+r)>>1;
    build(i<<1,l,mid);build(i<<1|1,mid+1,r);
    tr[i]=updata(tr[i<<1],tr[i<<1|1]);
}
void tch(int i,int l,int r,int x){
    if (l==r){tr[i]=(tree){ai[l],l};return;}
    int mid=(l+r)>>1;
    if (x<=mid) tch(i<<1,l,mid,x);
    else tch(i<<1|1,mid+1,r,x);
    tr[i]=updata(tr[i<<1],tr[i<<1|1]);
}
tree ask(int i,int l,int r,int ll,int rr){
    if (ll<=l&&r<=rr) return tr[i];
    int mid=(l+r)>>1;tree c1,c2;
    bool f1,f2;f1=f2=false;
    if (ll<=mid){f1=true;c1=ask(i<<1,l,mid,ll,rr);}
    if (rr>mid){f2=true;c2=ask(i<<1|1,mid+1,r,ll,rr);}
    if (f1&&f2) return updata(c1,c2);
    if (f1) return c1;
    return c2;}
void upd(int u){tp[u].sz=tp[tp[u].l].sz+1+tp[tp[u].r].sz;}
bool bal(int u){
    if (cmp((LD)max(tp[tp[u].l].sz,tp[tp[u].r].sz)*1.,alp*(LD)tp[u].sz)>0) return false;
    return true;
}
void ins(int &u,int k,point x,LD l,LD r){
    if (!u){
        bi[++bz]=x;ai[k]=bz;
        tp[u=++tt]=(use){0,0,1,bz,l,r};
        vi[bz]=(l+r)/2.;
        return;
    }if (bi[tp[u].po]==x){ai[k]=tp[u].po;return;}
    LD mid=(l+r)/2.;
    if (x<bi[tp[u].po]) ins(tp[u].l,k,x,l,mid);
    else ins(tp[u].r,k,x,mid,r);
    upd(u);
    if (!bal(tp[u].l)||!bal(tp[u].r)) uf=u;
}
void dfs(int u){
    if (!u) return;
    dfs(tp[u].l);
    zh[++zt]=tp[u];id[++iz]=u;
    dfs(tp[u].r);
}
void reb(int &u,int l,int r,LD ll,LD rr){
    if (l>r){u=0;return;}
    int mid=(l+r)>>1;LD mm=(ll+rr)/2.;
    tp[u=id[iz--]]=zh[mid];
    vi[tp[u].po]=mm;
    tp[u].le=ll;tp[u].re=rr;
    reb(tp[u].l,l,mid-1,ll,mm);
    reb(tp[u].r,mid+1,r,mm,rr);
    upd(u);
}
void rebuild(int &u){iz=zt=0;dfs(u);reb(u,1,zt,tp[u].le,tp[u].re);}
int main(){
    int i,n,m,l,r,k;char ch;
    n=in();m=in();
    for (i=1;i<=n;++i) ai[i]=1;
    build(1,1,n);
    bi[bz=1]=(point){0,0};
    tp[0]=(use){0,0,0,0,0.,0.};
    tp[rt=tt=1]=(use){0,0,1,1,0.,1.};
    for (i=1;i<=m;++i){
        ch=chin();l=in();r=in();
        if (ch=='C'){
            k=in();uf=0;
            ins(rt,k,(point){ai[l],ai[r]},0.,1.);
            if (uf){
                if (!bal(tp[uf].l)) rebuild(tp[uf].l);
                if (!bal(tp[uf].r)) rebuild(tp[uf].r);
            }else if (!bal(rt)) rebuild(rt);
            tch(1,1,n,k);
        }else{
            tree cc=ask(1,1,n,l,r);
            printf("%d\n",cc.mp);
        }
    }
}
View Code

 

posted @ 2016-06-02 11:05  Rivendell  阅读(1007)  评论(0编辑  收藏  举报