zoukankan      html  css  js  c++  java
  • 题目中的树很大,不能直接建出。
    但是题目中接树的次数较少,可以考虑把每棵树缩成一个点。
    把每个接上的树进行标号,称为小树。
    在倍增时距离的计算都计算的是小树的根的距离。
    处理出倍增数组$f_{x,i}$表示$x$号小树向上跳$2^i$步后走到哪个点(被缩的),$d_{x,i}$表示$x$号小树向上跳$2^i$步后走了多远。和$dep_{x}$表示$x$号小树的深度。
    可以直接按照定义计算。
    接下来考虑询问。假设当前询问点是$a,b$且$dep_{a}>=dep_{b}$
    特判掉询问点在同一棵小树内的情况。
    分2种情况讨论:
    1.$b$不是$a$的祖先。
    设$lc=lca(a,b)$
    将$a,b$跳到对应小树的根。
    接下来把$a,b$跳到$lc$的下面一个点。
    把$a,b$跳到分别的父亲。再统计$a,b$在$lc$的小树上的距离。
    同时累加答案。
    2.$b$是$a$的祖先
    设$lc=lca(x,y)$
    将$a$跳到对应小树的根。
    接下来把$a,b$跳到$lc$的下面一个点。
    把$a$跳到分别的父亲。再统计$a,b$在$lc$的小树上的距离。
    同时累加答案。
    我们在跳的过程中要求大树上的一个点$x$在原树上对应的点。假设$x$在编号为$y$的小树内部。
    注意到$x$对应的小树在原树上的节点的编号是连续的,可持久化线段树合并后在$y$的线段树上二分即可。
    思路较简单,但是代码很难写。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define N 200010
    int n,m,q,il[N],ss[N*30],ir[N],ct=1,sz[N],x[N],y[N],f[N][20],d[N][20],ff[N][20],gg[N][20],dd[N],dv[N],lc[N*30],rc[N*30],bg[N],mn[N],cc,rt[N],rr[N],rg[N];
    vector<int>g[N],h[N];
    int mg(int o,int p){
        if(!o||!p)return o+p;
        int t=++cc;
        ss[t]=ss[p]+ss[o];
        lc[t]=mg(lc[o],lc[p]);
        rc[t]=mg(rc[o],rc[p]);
        return t;
    }
    void mod(int &o,int l,int r,int x,int y){
        if(!o)o=++cc;
        if(l==r){
            ss[o]++;
            return;
        }
        int md=(l+r)/2;
        x<=md?mod(lc[o],l,md,x,y):mod(rc[o],md+1,r,x,y);
        ss[o]=ss[lc[o]]+ss[rc[o]];
    }
    int qu(int o,int l,int r,int x){
        if(l==r)return l;
        int md=(l+r)/2;
        if(x<=ss[lc[o]])
            return qu(lc[o],l,md,x);
        return qu(rc[o],md+1,r,x-ss[lc[o]]);
    }
    int qs(int o,int l,int r,int x){
        if(l==r)return ss[o];
        int md=(l+r)/2;
        if(x<=md)return qs(lc[o],l,md,x);
        return qs(rc[o],md+1,r,x)+ss[lc[o]];
    }
    void d1(int x,int fa){
        mn[x]=x;
        sz[x]=1;
        ff[x][0]=fa;
        mod(rt[x],1,n,x,1);
        dd[x]=dd[fa]+1;
        for(int y:g[x])
            if(y!=fa){
                d1(y,x);
                rt[x]=mg(rt[x],rt[y]);
                mn[x]=min(mn[x],mn[y]);
                sz[x]+=sz[y];
            }
    }
    int fd(int x){
        int l=1,r=ct,ans;
        while(l<=r){
            int md=(l+r)/2;
            if(il[md]<=x&&x<=ir[md])return md;
            if(x<il[md])r=md-1;
            else l=md+1;
        }
    }
    int lca(int x,int y){
        if(dd[x]>dd[y])swap(x,y);
        for(int i=19;~i;i--)
            if(dd[ff[y][i]]>=dd[x])
                y=ff[y][i];
        if(x==y)return x;
        for(int i=19;~i;i--)
            if(ff[x][i]!=ff[y][i])
                x=ff[x][i],y=ff[y][i];
        return ff[y][0];
    }
    int di(int x,int y){
        int lc=lca(x,y);
        return dd[x]+dd[y]-2*dd[lc];
    }
    int ll(int x,int y){
        if(dv[x]>dv[y])swap(x,y);
        for(int i=19;~i;i--)
            if(dv[f[y][i]]>=dv[x])
                y=f[y][i];
        if(x==y)return x;
        for(int i=19;~i;i--)
            if(f[x][i]!=f[y][i])
                x=f[x][i],y=f[y][i];
        return f[y][0];
    }
    int gt(int c,int e){
        int a=fd(c),b=fd(e),ans=0;
        if(a==b){
            int p1=qu(rt[rr[a]],1,n,-il[a]+c+1),p2=qu(rt[rr[b]],1,n,-il[b]+e+1);
            return di(p1,p2);
        }
        if(dv[a]<dv[b]){
            swap(a,b);
            swap(c,e);
        }
        int lv=ll(a,b),ok=0,p1=qu(rt[rr[a]],1,n,-il[a]+c+1),p2=qu(rt[rr[b]],1,n,-il[b]+e+1);
        if(lv==b){
            ans+=dd[p1]-dd[x[a]];
            ok=1;
            c=rg[a];
        }
        else{
            ans+=dd[p1]-dd[x[a]];
            ans+=dd[p2]-dd[x[b]];
            c=rg[a];
            e=rg[b];
        }
        for(int i=19;~i;i--){
            if(!ok&&dv[f[a][i]]>=dv[b]){
                ans+=d[a][i];
                c=rg[f[a][i]];
                a=f[a][i];
            }
            else if(ok&&dv[f[a][i]]>dv[b]){
                ans+=d[a][i];
                c=rg[f[a][i]];
                a=f[a][i];
            }
        }
        if(a==b){
            ans+=di(x[c],x[e]);
            return ans;
        }
        if(ok){
            int v1=qu(rt[x[f[a][0]]],1,n,y[a]-il[f[a][0]]+1),v2=qu(rt[rr[b]],1,n,e-il[b]+1);
            ans+=di(v1,v2);
            ans++;
            return ans;
        }
        for(int i=19;~i;i--)
            if(f[a][i]!=f[b][i]){
                ans+=d[a][i];
                ans+=d[b][i];
                c=x[f[a][i]];
                e=y[f[b][i]];
                a=f[a][i],b=f[b][i];
            }
        int v1=qu(rt[x[f[a][0]]],1,n,y[a]-il[f[a][0]]+1),v2=qu(rt[x[f[a][0]]],1,n,y[b]-il[f[b][0]]+1);
        ans+=2;
        ans+=di(v1,v2);
        return ans;
    }
    signed main(){
        //freopen("r.in","r",stdin);
        cin>>n>>m>>q;
        for(int i=1;i<n;i++){
            int x,y;
            cin>>x>>y;
            g[x].push_back(y);
            g[y].push_back(x);
        }
        d1(1,0);
        ff[1][0]=1;
        for(int i=1;i<20;i++)
            for(int j=1;j<=n;j++)
                ff[j][i]=ff[ff[j][i-1]][i-1];
        il[1]=1;
        ir[1]=n;
        x[1]=1;
        rr[1]=1;
        for(int i=2;i<=m+1;i++){
            cin>>x[i]>>y[i];
            int p=fd(y[i]);
            ct++;
            il[ct]=ir[ct-1]+1;
            g[p].push_back(ct);
            g[ct].push_back(p);
            rg[ct]=qs(rt[x[i]],1,n,x[i])+il[ct]-1;
            f[ct][0]=p;
            ir[ct]=il[ct]+sz[x[i]]-1;
            rr[ct]=x[i];
        }
        for(int i=2;i<=ct;i++){
            int t=qu(rt[x[f[i][0]]],1,n,-il[f[i][0]]+y[i]+1);
            dv[i]=dv[f[i][0]]+1;
            bg[i]=mn[x[i]];
            d[i][0]=di(t,x[f[i][0]])+1;
        }
        f[1][0]=1;
        for(int i=1;i<20;i++)
            for(int j=1;j<=ct;j++){
                f[j][i]=f[f[j][i-1]][i-1];
                d[j][i]=d[f[j][i-1]][i-1]+d[j][i-1];
            }
        while(q--){
            int x,y;
            cin>>x>>y;
            cout<<gt(x,y)<<'
    ';
        }
    }
    View Code
  • 相关阅读:
    【SPOJ1825】Free Tour II-点分治+桶排序
    【BZOJ3238】差异(AHOI2013)-后缀自动机+树形DP
    Vacation
    Function
    Path
    杭电oj初体验之 Code
    挑7
    行游散记!
    坐标移动
    STL之pair类型
  • 原文地址:https://www.cnblogs.com/cszmc2004/p/13183705.html
Copyright © 2011-2022 走看看