zoukankan      html  css  js  c++  java
  • dtoi4545「HNOI2016」树

    题意:

         https://loj.ac/p/2050

    题解:

         此题思路非常清晰,最后的大树可以看做是由 $m+1$ 个节点,每个节点内部又是一棵树组成的。

         考虑外层的树怎么建,对于一个插入操作,可以先二分它的父亲是哪一个节点,顺便还可以求一下模板树的某个子树的第 $k$ 大来确定到底是连在谁身上,用dfs序+主席树就可以维护了,还要维护一下每个节点最上面的点的真实深度(用longlong存)。

         内层的树不需要建,只需要知道根节点是哪个就可以了。

         然后处理查询操作,查询操作要做的就是求出两个点及其lca的深度就行,两个点的深度很好求,用所在的节点的根的深度+模板树中该点和这个节点的根的深度之差就行。求lca的话,先求外层的lca,再求里层的lca,最后算深度。这里稍微分下类,考虑下外层节点的关系就可以了。代码其实非常好写,也没啥细节。

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    int n,m,q,dfn[100003],df[100002],tim,fa[22][100003],dep[100003],zjds[100003],cnt,rt[100002];
    int fa2[22][100003],dep2[100003];
    long long sum[100003];
    vector<int>g[100003];
    typedef struct{
        int ls,rs,sum;
    }XDS;
    typedef struct{
        int rt,x;long long dep;
    }P;
    XDS xds[4000002];
    P p[100003];
    void dfs(int x,int y){
        zjds[x]=1;dep[x]=dep[y]+1;fa[0][x]=y;dfn[x]=++tim;df[tim]=x;
        for (int i=0;i<g[x].size();i++)
        if (g[x][i]!=y)
        {
            dfs(g[x][i],x);zjds[x]+=zjds[g[x][i]];
        }
    }
    int lca(int x,int y){
        if (dep[x]<dep[y])swap(x,y);
        int k=dep[x]-dep[y];
        for (int i=0;i<=20;i++)
        if ((1<<i)&k)x=fa[i][x];
        if (x==y)return x;
        for (int i=20;i>=0;i--)
        if (fa[i][x]!=fa[i][y])
        {
            x=fa[i][x];y=fa[i][y];
        }
        return fa[0][x];
    }
    void gengxin(int r1,int r2,int begin,int end,int wz){
        if (begin==end)
        {
            xds[r2].sum=xds[r1].sum+1;
            return;
        }
        int mid=(begin+end)/2;
        if (wz<=mid)
        {
            xds[r2].rs=xds[r1].rs;xds[r2].ls=++cnt;
            gengxin(xds[r1].ls,xds[r2].ls,begin,mid,wz);
        }
        else
        {
            xds[r2].ls=xds[r1].ls;xds[r2].rs=++cnt;
            gengxin(xds[r1].rs,xds[r2].rs,mid+1,end,wz);
        }
        xds[r2].sum=(xds[xds[r2].ls].sum+xds[xds[r2].rs].sum);
    }
    int chaxun(int r1,int r2,int begin,int end,int k){
        if (begin==end)return begin;
        int mid=(begin+end)/2;
        if (xds[xds[r2].ls].sum-xds[xds[r1].ls].sum>=k)return chaxun(xds[r1].ls,xds[r2].ls,begin,mid,k);
        else return chaxun(xds[r1].rs,xds[r2].rs,mid+1,end,k-(xds[xds[r2].ls].sum-xds[xds[r1].ls].sum));
    }
    int fin(long long x){
        int lef=1,righ=m+1,mid;
        while(lef<righ)
        {
            mid=(lef+righ)/2;
            if (sum[mid]>=x)righ=mid;else lef=mid+1;
        }
        return lef;
    }
    int findd(long long x){
        int lef=fin(x);
        return chaxun(rt[dfn[p[lef].rt]-1],rt[dfn[p[lef].rt]+zjds[p[lef].rt]-1],1,n,x-sum[lef-1]);
    }
    long long jsdep(long long x){
        int lef=fin(x),wz=findd(x);
        return p[lef].dep+dep[wz]-dep[p[lef].rt];
    }
    bool isfa2(int x,int y){
        int k=dep2[x]-dep2[y];
        for (int i=0;i<=20;i++)
        if ((1<<i)&k)x=fa2[i][x];
        return (x==y);
    }
    long long jslca(long long x,long long y){
        int fx=fin(x),fy=fin(y);
        if (dep2[fx]<dep2[fy]){swap(x,y);swap(fx,fy);}
        if (fx==fy)
        {
            int lc=lca(findd(x),findd(y));
            return p[fx].dep+dep[lc]-dep[p[fx].rt];
        }
        else if (isfa2(fx,fy))
        {
            int k=dep2[fx]-dep2[fy]-1;
            for (int i=0;i<=20;i++)
            if ((1<<i)&k)fx=fa2[i][fx];
            int lc=lca(p[fx].x,findd(y));
            return p[fy].dep+dep[lc]-dep[p[fy].rt];
        }
        else
        {
            int k=dep2[fx]-dep2[fy];
            for (int i=0;i<=20;i++)
            if ((1<<i)&k)fx=fa2[i][fx];
            for (int i=20;i>=0;i--)
            if (fa2[i][fx]!=fa2[i][fy])
            {
                fx=fa2[i][fx];fy=fa2[i][fy];
            }
            int lc=lca(p[fx].x,p[fy].x);
            fx=fa2[0][fx];
            return p[fx].dep+dep[lc]-dep[p[fx].rt];
        }
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&q);
        for (int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);g[u].push_back(v);g[v].push_back(u);
        }
        dfs(1,0);
        for (int i=1;i<=n;i++)
        {
            rt[i]=++cnt;gengxin(rt[i-1],rt[i],1,n,df[i]);
        }
        for (int i=1;i<=20;i++)
        for (int j=1;j<=n;j++)
        fa[i][j]=fa[i-1][fa[i-1][j]];
        p[1].rt=1;p[1].dep=0;sum[1]=n;dep2[1]=0;
        for (int i=2;i<=m+1;i++)
        {
            int a;long long b;
            scanf("%d%lld",&a,&b);
            int lef=1,righ=i-1,mid,nw;
            while(lef<righ)
            {
                mid=(lef+righ)/2;
                if (sum[mid]>=b)righ=mid;else lef=mid+1;
            }
            nw=lef;fa2[0][i]=nw;dep2[i]=dep2[nw]+1;
            p[i].rt=a;p[i].x=chaxun(rt[dfn[p[nw].rt]-1],rt[dfn[p[nw].rt]+zjds[p[nw].rt]-1],1,n,b-sum[nw-1]);
            p[i].dep=p[nw].dep+(dep[p[i].x]-dep[p[nw].rt])+1;
            sum[i]=sum[i-1]+zjds[a];
        }
        for (int i=1;i<=20;i++)
        for (int j=1;j<=m+1;j++)
        fa2[i][j]=fa2[i-1][fa2[i-1][j]];
        for (int i=1;i<=q;i++)
        {
            long long a,b;
            scanf("%lld%lld",&a,&b);
            printf("%lld
    ",jsdep(a)+jsdep(b)-2*jslca(a,b));
        }
        return 0;
    }
  • 相关阅读:
    yii框架入门学习笔记二 根据数据表创建model类
    mysql数据库操纵类升级版
    yii框架入门学习笔记三 完善登陆功能
    java发送http的get、post请求
    Please ensure that adb is correctly located at 'D:\androidsdkwindows\platf
    CodeIgniter框架入门教程——第一课 Hello World!
    C#正则表达式应用
    common lisp 笔记2 a cd ripper
    javascript的String函数
    修改linux下sudo设置
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/14404086.html
Copyright © 2011-2022 走看看