bzoj 3600: 沒有人的算術

Description

Solution

我們可以給每一個數欽定一個權值 , 這樣就可以 \(O(1)\) 比較大小了.
考慮怎麼確定權值:
用平衡樹來維護 , 我們假設根節點管轄 \([1,2^{60}]\) 的數 , 根節點的右兒子都比根節點權值大 , 左兒子權值都都比根節點小
左兒子管轄 \([1,2^{59}-1]\) , 右兒子管轄 \([2^{59}+1,2^{60}]\) 這樣分下去 , 但是插入可能會導致不平衡 , 使得深度過大, 不斷除以 \(2\) 最後變成小數 , 導致精度誤差 , 最後無法比較大小 .
於是我們就採用替罪羊樹維護 , 這樣就可以保證深度了 , 當某個節點 \(x\) 滿足 \(max(size[lson],size[rson])>=size[x]*0.75\) 我們就暴力重構 .
詢問用線段樹維護 , 每個節點維護每個位置在替罪羊樹上對應的節點編號 , 每一次通過查詢權值就可以比較大小 .

#include<bits/stdc++.h>
#define LS (o<<1)
#define RS (o<<1|1)
#define I set<int>::iterator
using namespace std;
typedef long long ll;
const int N=1e6+10;const ll M=1ll<<60;
int n,Q,ls[N],rs[N],P;
ll w[N];int tr[N*4],id[N];
struct data{
    int x,y;
    inline bool operator <(const data &p)const{
        return x!=p.x?w[x]<w[p.x]:w[y]<w[p.y];}
}v[N];
inline int merge(int x,int y){
    return id[x]==id[y]?x:(w[id[x]]>w[id[y]]?x:y);
}
inline void build(int l,int r,int o){
    if(l==r){tr[o]=l;id[l]=0;return ;}
    int mid=(l+r)>>1;
    build(l,mid,LS);build(mid+1,r,RS);
    tr[o]=merge(tr[LS],tr[RS]);
}
inline void ins(int l,int r,int o,int sa){
    if(l==r){id[l]=P;return ;}
    int mid=(l+r)>>1;
    if(sa<=mid)ins(l,mid,LS,sa);
    else ins(mid+1,r,RS,sa);
    tr[o]=merge(tr[LS],tr[RS]);
}
inline int qry(int l,int r,int o,int sa,int se){
    if(sa<=l && r<=se)return tr[o];
    int mid=(l+r)>>1;
    if(se<=mid)return qry(l,mid,LS,sa,se);
    if(sa>mid)return qry(mid+1,r,RS,sa,se);
    return merge(qry(l,mid,LS,sa,mid),qry(mid+1,r,RS,mid+1,se));
}
ll _l,_r;int *t,rt=0,tt=0,sz[N],top=0,st[N];
inline void insert(ll l,ll r,int &x,data p){
    ll mid=(l+r)>>1;
    if(!x)x=++tt,w[x]=mid,v[x]=p;
    ++sz[x];
    if(v[x].x==p.x && v[x].y==p.y){P=x;return ;}
    if(p<v[x])insert(l,mid-1,ls[x],p);
    else insert(mid+1,r,rs[x],p);
    if(max(sz[ls[x]],sz[rs[x]])>sz[x]*0.75)t=&x,_l=l,_r=r;
}
inline void dfs(int x){
    if(!x)return ;
    dfs(ls[x]);st[++top]=x;
    dfs(rs[x]);
}
inline void build(int l,int r,ll L,ll R,int &x){
    int mid=(l+r)>>1;
    x=st[mid],w[x]=(L+R)>>1,ls[x]=rs[x]=0;
    if(l<mid)build(l,mid-1,L,w[x]-1,ls[x]);
    if(mid<r)build(mid+1,r,w[x]+1,R,rs[x]);
    sz[x]=sz[ls[x]]+sz[rs[x]]+1;
}
inline void Insert(data p){
    t=NULL,insert(1,M,rt,p);
    if(t!=NULL){
        top=0;
        dfs(*t);build(1,top,_l,_r,*t);
    }
}
int main(){
    freopen("calc.in","r",stdin);
    freopen("calc.out","w",stdout);
    cin>>n>>Q;
    build(1,n,1);
    char op[2];int x,y,k;
    while(Q--){
        scanf("%s%d%d",op,&x,&y);
        if(op[0]=='C'){
            Insert((data){id[x],id[y]});
            scanf("%d",&k);
            ins(1,n,1,k);
        }
        else printf("%d\n",qry(1,n,1,x,y));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章