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
  • 相关阅读:
    HDU 3681 Prison Break 越狱(状压DP,变形)
    POJ 2411 Mondriaan's Dream (状压DP,骨牌覆盖,经典)
    ZOJ 3471 Most Powerful (状压DP,经典)
    POJ 2288 Islands and Bridges (状压DP,变形)
    HDU 3001 Travelling (状压DP,3进制)
    POJ 3311 Hie with the Pie (状压DP)
    POJ 1185 炮兵阵地 (状压DP,轮廓线DP)
    FZU 2204 7
    POJ 3254 Corn Fields (状压DP,轮廓线DP)
    ZOJ 3494 BCD Code (数位DP,AC自动机)
  • 原文地址:https://www.cnblogs.com/cszmc2004/p/13183705.html
Copyright © 2011-2022 走看看