【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\n",ans);
    }
    return 0;
}
posted @ 2018-06-15 21:06  一剑霜寒十四洲  阅读(123)  评论(0编辑  收藏  举报