zoukankan      html  css  js  c++  java
  • 【bzoj3435】【uoj#55】[WC2014]紫荆花之恋 【动态树分治】【平衡树】

    难以置信我居然今生有幸独立调出了这样一道神题!orzorzCLJ!
    题目传送门
    题解:
    其实这道题思路不算复杂,但是代码难度特别比较高。
    由于点是一个一个加进来的,我们可不可以一步一步地构建一棵动态分治树呢?我们发现,一个点是原树中某个点的儿子,那么在分治树中它也可以是这个点的儿子。我们可以直接在分治树种把它们接起来。但是当树变得特别高时,每次查询的复杂度显然会爆炸。所以我们用替罪羊树的思想,用α值判一下,当某个子树变得极不平衡时重构一棵平衡的分治树。
    我们设当前的分治中心为u。移项得到
    dis(u,i)r[i]r[j]dis(u,j)
    但是i,j在同一棵子树内的情况要去掉。
    所以我们对每个分治中心u设两棵平衡树。第一棵维护子树内所有dis(u,i)r[i]的值,第二棵维护子树内所有dis(fa[u],i)r[i]的值。新加入一个点,我们就从这个点的父亲往根爬,同时加上父亲fa[u]的第一棵平衡树r[j]dis(fa[u],j)的值的个数,减去自己的第二棵平衡树r[j]dis(fa[u],j)的值的个数。感觉还是动态树分治的常见处理方法。平衡树当然是写替罪羊树啦!
    重构的时候注意一下细节就好了。
    在不同OJ上α的取值可能要不一样才能过。大部分OJα=0.83可过,洛谷要小一点,0.75可过,不然会T。总之多试几次取值就差不多了。
    代码好长啊!

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    inline int rd(){
        register char ch=getchar();
        register int res=0;
        while(ch<'0'||ch>'9'){
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            res=res*10+ch-'0';
            ch=getchar();
        }
        return res;
    }
    const int N=100005;
    const double alpha=0.75;
    int n,cnt,c[N],r[N],dep[N],dist[N],fa[N],siz[N],rt[N];
    int idx,head[N],to[N*2],nxt[N*2],dd[N*2],vis[N],pa[N][18];
    ll ans;
    bool ck[N],ck2[N];
    void adde(int u,int v,int d){
        to[++cnt]=v;
        nxt[cnt]=head[u];
        dd[cnt]=d;
        head[u]=cnt;
    }
    namespace bst{
        const int M=8000005;
        int cnt,val[M],siz[M],tot[M],pos[M],mmp[M],ch[M][2];
        struct scapegoattree{
            int rt,*goat;
            void clear(int k){
                if(!k){
                    return;
                }
                clear(ch[k][0]);
                mmp[++mmp[0]]=k;
                clear(ch[k][1]);
            }
            void clear(){
                clear(rt);
                rt=0;
            }
            void dfs(int k){
                if(!k){
                    return;
                }
                dfs(ch[k][0]);
                pos[++pos[0]]=k;
                dfs(ch[k][1]);
            }
            void build(int &k,int l,int r){
                if(l>r){
                    k=0;
                    return;
                }
                int mid=(l+r)/2;
                k=pos[mid];
                build(ch[k][0],l,mid-1);
                build(ch[k][1],mid+1,r);
                siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+1;
                tot[k]=tot[ch[k][0]]+tot[ch[k][1]]+1;
            }
            void rebuild(int &k){
                pos[0]=0;
                dfs(k);
                build(k,1,pos[0]);
            }
            void insert(int &k,int x){
                if(!k){
                    k=mmp[0]?mmp[mmp[0]--]:++cnt;
                    ch[k][0]=ch[k][1]=0;
                    val[k]=x;
                    siz[k]=tot[k]=1;
                    return;
                }
                siz[k]++;
                tot[k]++;
                if(x<=val[k]){
                    insert(ch[k][0],x);
                }else{
                    insert(ch[k][1],x);
                }
                if(tot[k]*alpha<max(tot[ch[k][0]],tot[ch[k][1]])){
                    goat=&k;
                }
            }
            void insert(int x){
                goat=0;
                insert(rt,x);
                if(goat){
                    rebuild(*goat);
                }
            }
            int get(int x){
                int k=rt,res=0;
                while(k){
                    if(x<val[k]){
                        k=ch[k][0];
                    }else{
                        res+=siz[ch[k][0]]+1;
                        k=ch[k][1];
                    }
                }
                return res;
            }
        }sgt[N][2];
    }
    int lca(int u,int v){
        if(dep[u]<dep[v]){
            swap(u,v);
        }
        int d=dep[u]-dep[v];
        for(int i=0;(1<<i)<=d;i++){
            if(d&(1<<i)){
                u=pa[u][i];
            }
        }
        if(u==v){
            return u;
        }
        for(int i=17;i>=0;i--){
            if(pa[u][i]!=pa[v][i]){
                u=pa[u][i];
                v=pa[v][i];
            }
        }
        return pa[u][0];
    }
    int dis(int u,int v){
        int tmp=lca(u,v);
        return dist[u]-dist[tmp]+dist[v]-dist[tmp];
    }
    int mi,root,sz;
    void dfsvis(int pre,int u){
        bst::sgt[u][0].clear();
        bst::sgt[u][1].clear();
        vis[u]=idx;
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=pre&&!ck2[v]){
                dfsvis(u,v);
            }
        }
    }
    int dfsroot(int pre,int u){
        int mx=0,siz=1,v,tmp;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=pre&&vis[v]==idx&&!ck[v]&&!ck2[v]){
                tmp=dfsroot(u,v);
                mx=max(mx,tmp);
                siz+=tmp;
            }
        }
        mx=max(mx,sz-siz);
        if(mx<mi){
            mi=mx;
            root=u;
        }
        return siz;
    }
    int dfssize(int pre,int u){
        int siz=1,v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=pre&&vis[v]==idx&&!ck[v]&&!ck2[v]){
                siz+=dfssize(u,v);
            }
        }
        return siz;
    }
    void build(int pre,int u,int d,bst::scapegoattree *t){
        t->insert(d-r[u]);
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=pre&&vis[v]==idx&&!ck[v]&&!ck2[v]){
                build(u,v,d+dd[i],t);
            }
        }
    }
    void dfs(int u){
        ck[u]=true;
        build(0,u,0,&bst::sgt[u][0]);
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(vis[v]==idx&&!ck[v]&&!ck2[v]){
                mi=sz=dfssize(u,v);
                dfsroot(u,v);
                fa[root]=u;
                rt[root]=v;
                siz[root]=sz;
                build(0,v,dd[i],&bst::sgt[root][1]);
                dfs(root);
            }
        }
    }
    void dfsclear(int pre,int u){
        ck[u]=false;
        int v;
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(v!=pre&&!ck2[v]){
                dfsclear(u,v);
            }
        }
    }
    void rebuild(int pre,int u){
        int tmp=pre;
        while(tmp){
            ck2[tmp]=true;
            tmp=fa[tmp];
        }
        idx++,dfsvis(pre,u);
        dfsroot(pre,u);
        fa[root]=pre;
        rt[root]=u;
        siz[root]=sz;
        if(pre){
            build(0,u,dis(pre,u),&bst::sgt[root][1]);
        }
        dfs(root);
        dfsclear(pre,u);
        tmp=pre;
        while(tmp){
            ck2[tmp]=false;
            tmp=fa[tmp];
        }
    }
    int main(){
        rd(),n=rd();
        for(int i=1;i<=n;i++){
            fa[i]=pa[i][0]=rd()^(ans%1000000000),c[i]=rd(),r[i]=rd();
            siz[i]=1;
            rt[i]=i;
            if(i==1){
                bst::sgt[1][0].insert(c[i]-r[i]);
                puts("0");
                continue;
            }
            adde(pa[i][0],i,c[i]);
            adde(i,pa[i][0],c[i]);
            dep[i]=dep[pa[i][0]]+1;
            dist[i]=dist[pa[i][0]]+c[i];
            for(int j=1;(1<<j)<=dep[i];j++){
                pa[i][j]=pa[pa[i][j-1]][j-1];
            }
            ans+=bst::sgt[fa[i]][0].get(r[i]-dis(fa[i],i));
            for(int u=fa[i];fa[u];u=fa[u]){
                ans+=bst::sgt[fa[u]][0].get(r[i]-dis(fa[u],i));
                ans-=bst::sgt[u][1].get(r[i]-dis(fa[u],i));
            }
            int tmp=0;
            bst::sgt[i][0].insert(0-r[i]);
            for(int u=i;fa[u];u=fa[u]){
                siz[fa[u]]++;
                bst::sgt[fa[u]][0].insert(dis(fa[u],i)-r[i]);
                bst::sgt[u][1].insert(dis(fa[u],i)-r[i]);
                if(siz[fa[u]]*alpha<siz[u]){
                    tmp=fa[u];
                }
            }
            if(tmp){
                mi=sz=siz[tmp];
                rebuild(fa[tmp],rt[tmp]);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    MarkDown学习记录
    AngularJS+Ionic开发-2.项目结构介绍
    【二分+贪心+倍增】【NOIP2012】疫情控制
    【考试总结】NOIP模拟 test11-1
    【考试总结】NOIP模拟 test10-27
    【考试总结】AHSOFNU&QZQZ test10-25
    【差分+二分答案】【NOIP2012】借教室
    【动态规划】【NOIP2015】子串
    【高精度+贪心】【NOIP2012】国王游戏
    ICPC Central Russia Regional Contest (CRRC 19)题解
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476857.html
Copyright © 2011-2022 走看看