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;
}
原文地址:https://www.cnblogs.com/1124828077ccj/p/14404086.html