bzoj4539: [Hnoi2016]树

来源:互联网 发布:淘宝最好的店铺 编辑:程序博客网 时间:2024/06/06 16:56

题目链接

bzoj4539

题目描述

Description

  小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了。开始,小A只有一棵结点数为N的树,结点的编号为1,2,…,N,其中结点1为根;我们称这颗树为模板树。小A决定通过这棵模板树来构建一颗大树。构建过程如下:(1)将模板树复制为初始的大树。(2)以下(2.1)(2.2)(2.3)步循环执行M次(2.1)选择两个数字a,b,其中1<=a<=N,1<=b<=当前大树的结点数。(2.2)将模板树中以结点a为根的子树复制一遍,挂到大树中结点b的下方(也就是说,模板树中的结点a为根的子树复制到大树中后,将成为大树中结点b的子树)。(2.3)将新加入大树的结点按照在模板树中编号的顺序重新编号。例如,假设在进行2.2步之前大树有L个结点,模板树中以a为根的子树共有C个结点,那么新加入模板树的C个结点在大树中的编号将是L+1,L+2,…,L+C;大树中这C个结点编号的大小顺序和模板树中对应的C个结点的大小顺序是一致的。下面给出一个实例。假设模板树如下图:
这里写图片描述
根据第(1)步,初始的大树与模板树是相同的。在(2.1)步,假设选择了a=4,b=3。运行(2.2)和(2.3)后,得到新的大树如下图所示
这里写图片描述
现在他想问你,树中一些结点对的距离是多少。

Input

  第一行三个整数:N,M,Q,以空格隔开,N表示模板树结点数,M表示第(2)中的循环操作的次数,Q 表示询问数量。接下来N-1行,每行两个整数 fr,to,表示模板树中的一条树边。再接下来M行,每行两个整数x,to,表示将模板树中 x 为根的子树复制到大树中成为结点to的子树的一次操作。再接下来Q行,每行两个整数fr,to,表示询问大树中结点 fr和 to之间的距离是多少。

Output

  输出Q行,每行一个整数,第 i行是第 i个询问的答案。

Sample Input

5 2 3
1 4
1 3
4 2
4 5
4 3
3 2
6 9
1 8
5 3

Sample Output

6
3
3

HINT

经过两次操作后,大树变成了下图所示的形状:
这里写图片描述
结点6到9之间经过了6条边,所以距离为6;类似地,结点1到8之间经过了3条边;结点5到3之间也经过了3条边。

题解

我们将每次操作的一颗子树看成一个块,可以得到一颗树。我们可以二分得到一个节点属于哪个块,以及它在块中是排第几,那么可以用主席树维护新树和模板树节点的对应关系。
对于一次询问,如果他们在同一块,则直接在模板树中求lca,否则块之间在新树中倍增,块之内在模板树中求就可以了。


#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int N=100010;typedef long long ll;struct node{    int ls,rs,d;}t[N*20];struct tree{    struct edge{        int x,nex,data;    }e[N*2];    int f[N][20],dep[N],first[N],size[N],tot;    ll dis[N];    int dfn[N],pos[N],ti;    void add(int x,int y,int d){        e[++tot].x=y;        e[tot].data=d;        e[tot].nex=first[x];        first[x]=tot;    }    void dfs(int x,int y){        dfn[x]=++ti; pos[ti]=x;        f[x][0]=y; dep[x]=dep[y]+1;        for(int i=1;i<=17;i++) f[x][i]=f[f[x][i-1]][i-1];        for(int i=first[x];i;i=e[i].nex)        if(e[i].x!=y){            dis[e[i].x]=dis[x]+e[i].data;            dfs(e[i].x,x);            size[x]+=size[e[i].x];        }        size[x]++;    }    int LCA(int x,int y){        if(dep[x]<dep[y]) std::swap(x,y);        for(int i=17;~i;i--)        if(dep[f[x][i]]>=dep[y]) x=f[x][i];        if(x==y) return x;        for(int i=17;~i;i--)        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];        return f[x][0];    }    int s_lca(int x,int y){        for(int i=17;~i;i--)        if(dep[f[x][i]]>dep[y]) x=f[x][i];        return x;    }}t1,t2;int num,n,m,q,tmp1,tmp2,tmp,lca,cnt;int top[N],st[N],dis[N],rt[N];ll a[N],s,ans,x,y;void insert(int &k,int l,int r,int x){    t[++cnt]=t[k]; k=cnt; t[k].d++;    if(l==r) return;    int mid=(l+r)>>1;    if(x<=mid) insert(t[k].ls,l,mid,x);    else insert(t[k].rs,mid+1,r,x);}int query(int k1,int k2,int l,int r,int x){    if(l==r) return l;    int tmp=t[t[k1].ls].d-t[t[k2].ls].d;    int mid=(l+r)>>1;    if(tmp>=x) return query(t[k1].ls,t[k2].ls,l,mid,x);    else return query(t[k1].rs,t[k2].rs,mid+1,r,x-tmp);}int Find(ll x){    int l=1,r=num+1,mid;    while(r-l>1){        mid=(l+r)>>1;        if(a[mid]>x) r=mid;        else l=mid;    }    return l;}int Get(ll x,int tmp){    if(tmp==1) return x;    x=x-a[tmp]+1;    int r=t1.dfn[st[tmp]]+t1.size[st[tmp]]-1;    int l=t1.dfn[st[tmp]]-1;    return query(rt[r],rt[l],1,n,x);}int main(){    freopen("tree.in","r",stdin);    freopen("tree.out","w",stdout);    scanf("%d%d%d",&n,&m,&q);    for(int i=1;i<n;i++){        scanf("%lld%lld",&x,&y);        t1.add(x,y,1); t1.add(y,x,1);    }    t1.dfs(1,0);    for(int i=1;i<=n;i++){        rt[i]=rt[i-1];        insert(rt[i],1,n,t1.pos[i]);    }    a[++num]=1; s=n; st[num]=1;    for(int i=1;i<=m;i++){        scanf("%lld%lld",&x,&y);        a[++num]=s+1; s+=t1.size[x];        tmp=Find(y); top[num]=Get(y,tmp); st[num]=x;        dis[num]=t1.dis[x];        t2.add(num,tmp,t1.dis[Get(y,tmp)]-dis[tmp]+1);        t2.add(tmp,num,t1.dis[Get(y,tmp)]-dis[tmp]+1);    }    t2.dfs(1,0);    for(int i=1;i<=q;i++){        scanf("%lld%lld",&x,&y);        tmp1=Find(x),tmp2=Find(y);        if(tmp1==tmp2){            ans=t1.dis[Get(x,tmp1)]+t1.dis[Get(y,tmp2)]-2*t1.dis[t1.LCA(Get(x,tmp1),Get(y,tmp2))];            printf("%lld\n",ans);            continue;        }        ans=0;        lca=t2.LCA(tmp1,tmp2);        if(t2.dep[tmp1]<t2.dep[tmp2]) swap(tmp1,tmp2),swap(x,y);        if(lca!=tmp2){            ans+=t1.dis[Get(y,tmp2)]-dis[tmp2]+1,y=t2.s_lca(tmp2,lca);            ans+=t2.dis[tmp2]-t2.dis[y]; y=top[y];        } else y=Get(y,tmp2);        ans+=t1.dis[Get(x,tmp1)]-dis[tmp1]+1,x=t2.s_lca(tmp1,lca);        ans+=t2.dis[tmp1]-t2.dis[x]; x=top[x];         ans+=t1.dis[x]+t1.dis[y]-2*t1.dis[t1.LCA(x,y)];        printf("%lld\n",ans);    }    return 0;}
0 0