BZOJ4539: [Hnoi2016]树

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之间的距离是多少。

N,M,Q<=100000

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条边。

题解Here!

真心不想复制了,请您戳这里。

顺手贴上代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define MAXN 100010
using namespace std;
int n,m,q,c=1;
int id[MAXN],pos[MAXN],tree_size[MAXN];
inline long long read(){long long date=0,w=1;char c=0;while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}return date*w;
}
namespace ST{int d=1,e=1;int head[MAXN],deep[MAXN],f[MAXN][20];struct Tree{int next,to;}a[MAXN<<1];inline void add(int x,int y){a[d].to=y;a[d].next=head[x];head[x]=d++;a[d].to=x;a[d].next=head[y];head[y]=d++;}void buildtree(int rt){tree_size[rt]=1;id[rt]=e;pos[e++]=rt;for(int i=head[rt];i;i=a[i].next){int will=a[i].to;if(!deep[will]){deep[will]=deep[rt]+1;f[will][0]=rt;buildtree(will);tree_size[rt]+=tree_size[will];}}}void step(){for(int i=1;i<=19;i++)for(int j=1;j<=n;j++)f[j][i]=f[f[j][i-1]][i-1];}int LCA(int x,int y){if(deep[x]<deep[y])swap(x,y);for(int i=19;i>=0;i--)if(deep[f[x][i]]>=deep[y])x=f[x][i];if(x==y)return x;for(int i=19;i>=0;i--)if(f[x][i]!=f[y][i]){x=f[x][i];y=f[y][i];}return f[x][0];}inline long long dis(int x,int y){return abs(deep[x]-deep[y]);}inline long long dis_lca(int x,int y,int rt){return deep[LCA(x,y)]-deep[rt];}
}
namespace CT{int d=1,size=1,root[MAXN];struct Charman_Tree{int l,r,sum;}a[MAXN*22];struct Right{int root,x;long long v;friend bool operator <(const Right p,const Right q){return p.v<q.v;}}right[MAXN];void insert(int k,int l,int r,int &rt){a[size]=a[rt];rt=size++;a[rt].sum++;if(l==r)return;int mid=l+r>>1;if(k<=mid)insert(k,l,mid,a[rt].l);else insert(k,mid+1,r,a[rt].r);}int query(int i,int j,int l,int r,int k){if(l==r)return l;int mid=l+r>>1,t=a[a[j].l].sum-a[a[i].l].sum;if(k<=t)return query(a[i].l,a[j].l,l,mid,k);else return query(a[i].r,a[j].r,mid+1,r,k-t);}inline void buildtree(){root[0]=0;a[0].l=a[0].r=a[0].sum=0;for(int i=1;i<=n;i++){root[i]=root[i-1];insert(pos[i],0,n,root[i]);}}inline int kth(int l,int r,int k){return query(root[l],root[r],0,n,k);}inline void insert_node(int root,int x){right[d]=(Right){root,x,right[d-1].v+tree_size[root]};d++;}inline void query_node(long long v,int &root,int &y,int &x){Right p=*lower_bound(right+1,right+d,(Right){0,0,v});root=p.root;x=p.x;int rank=v+tree_size[root]-p.v;y=kth(id[root]-1,id[root]+tree_size[root]-1,rank);}
}
namespace BT{int d=1,head[MAXN],deep[MAXN],val[MAXN],f[MAXN][20];long long dis[MAXN];struct Tree{int next,to;long long w;}a[MAXN<<1];inline void add(int u,int v,long long w){a[d].to=v;a[d].w=w;a[d].next=head[u];head[u]=d++;a[d].to=u;a[d].w=w;a[d].next=head[v];head[v]=d++;}void buildtree(int rt){int will;for(int i=head[rt];i;i=a[i].next){will=a[i].to;if(!deep[will]){deep[will]=deep[rt]+1;dis[will]=dis[rt]+a[i].w;f[will][0]=rt;buildtree(will);}}}void step(){for(int i=1;i<=19;i++)for(int j=1;j<=c-1;j++)f[j][i]=f[f[j][i-1]][i-1];}int LCA(int x,int y,int &u,int &v){if(x==y)return x;if(deep[x]<deep[y]){swap(x,y);swap(u,v);}for(int i=19;i>=0;i--)if(deep[f[x][i]]>deep[y])x=f[x][i];if(f[x][0]==y){u=val[x];return y;}else if(deep[x]!=deep[y])x=f[x][0];for(int i=19;i>=0;i--)if(f[x][i]!=f[y][i]){x=f[x][i];y=f[y][i];}u=val[x];v=val[y];return f[x][0];}inline long long dist(int u,int v,int lca){return dis[u]+dis[v]-dis[lca]*2;}
}
inline void solve(long long x,long long y){long long dist;int r1,x1,y1,h1;int r2,x2,y2,h2;CT::query_node(x,r1,y1,x1);CT::query_node(y,r2,y2,x2);h1=y1;h2=y2;int lca=BT::LCA(x1,x2,h1,h2),r=CT::right[lca].root;dist=ST::dis(r1,y1)+ST::dis(r2,y2)-ST::dis_lca(h1,h2,r)*2+BT::dist(x1,x2,lca);printf("%lld\n",dist);
}
void work(){long long x,y;while(q--){x=read();y=read();solve(x,y);}
}
void init(){int x,y,rt;n=read();m=read();q=read();for(int i=1;i<n;i++){x=read();y=read();ST::add(x,y);}ST::deep[1]=1;ST::buildtree(1);ST::step();CT::buildtree();CT::insert_node(1,c++);for(int i=1;i<=m;i++){int u=read();long long v=read();CT::query_node(v,rt,y,x);CT::insert_node(u,c);BT::val[c]=y;int w=ST::dis(y,rt)+1;BT::add(x,c,w);c++;}BT::deep[1]=1;BT::dis[1]=0;BT::buildtree(1);BT::step();
}
int main(){init();work();return 0;
}

转载于:https://www.cnblogs.com/Yangrui-Blog/p/9343782.html

BZOJ4539: [Hnoi2016]树相关推荐

  1. 2019.03.25 bzoj4539: [Hnoi2016]树(主席树+倍增)

    传送门 题意:给一棵大树,令一棵模板树与这棵树相同,然后进行mmm次操作,每次选择模板树中的一个节点aaa和大树中一个节点bbb,把aaa这棵子树接在bbb上面,节点编号顺序跟aaa中的编号顺序相同. ...

  2. [暑假的bzoj刷水记录]

    (这篇我就不信有网站来扣) 这个暑假打算刷刷题啥的 但是写博客好累啊  堆一起算了 隔一段更新一下.  7月27号之前刷的的就不写了 , 写的累 代码不贴了,可以找我要啊.. 2017.8.27upd ...

  3. linux下gem卸载,gem 安装卸载pod

    Linux打包压缩.md Linux下打包压缩命令 下面学习一下压缩和打包的相关命令,首先得先明确两个概念,即:压缩和打包 .我们实际使用中一般是打包和压缩结合的使用,为了学习下面简要的介绍一下压缩文 ...

  4. # HNOI2012 ~ HNOI2018 题解

    HNOI2012 题解 [HNOI2012]永无乡 Tag:线段树合并.启发式合并 联通块合并问题. 属于\(easy\)题,直接线段树合并 或 启发式合并即可. [HNOI2012]排队 Tag:组 ...

  5. 2018十二月刷题列表

    Preface \(2018\)年的尾巴,不禁感慨自己这一年的蜕变只能用蜕变来形容了. 而且老叶说我们今年没的参加清北冬令营可以参加CCF在广州二中举办的冬令营,只要联赛\(390+\)就应该可以报. ...

  6. P3250 [HNOI2016]网络(利用堆建线段树 + 树剖)

    P3250 [HNOI2016]网络 做法有点神奇!!!利用堆作为节点建立一颗线段树,用堆维护线段树上点的信息. 说说查询操作,我们的目的是要查询,没有经过这个点的事件最大值,考虑如何维护. 我们定义 ...

  7. [HNOI2016]网络(树链剖分+线段树+大根堆)

    [HNOI2016]网络 problem solution 另辟蹊径,不把交互请求赋在新增路径上,反而把交互请求赋在树上除去该请求路径覆盖点的其它点上 显然,路径问题树剖是非常可以的. 那么一个点上的 ...

  8. [HNOI2016]网络 树链剖分,堆

    [HNOI2016]网络 LG传送门 表示乱搞比正解难想. 整体二分很好想吧. 但是为了好写快乐,我们选择三个\(\log\)的乱搞. 先树剖,线段树套堆维护区间最大值.对于一次修改,如果是插入,就把 ...

  9. [HNOI2016] 序列(线段树 + 莫队 + 倍增)

    problem luogu-P3246 心路历程+卡常历程+问题存疑 一直在想莫队的做法.发现左右指针的移动对应一段左/右端点固定的子序列,然后可以一个数代表一段相同的贡献. 就开始求 lsti,nx ...

最新文章

  1. decisiontreeregressor_机器学习算法-Decision Tree
  2. Redis 的机制为什么不会产生 ABA 问题
  3. Visual Studio 2013开发 mini-filter driver step by step (11) driver 签名
  4. python 板蓝根字典变量的创建
  5. [BZOJ1177][Apio2009]Oil
  6. eureka常见错误
  7. DeepFaceLab
  8. android手机做电脑的显示器,怎样用手机当电脑显示器
  9. 如何当好一个师长之软件开发篇
  10. python公开直播课_今晚Python与人工智能直播课来袭,Mars喊你快上车
  11. Kernel: 错误:__ib_cache_gid_add: unable to add gid fe80:0000:0000:0000:f816:3eff:fee8:d1de error=-28
  12. php 查询每个一号,SPOT系列卫星参数一览表 - 高分一号、高分二号卫星查询遥感数据购买 - 新闻资讯 - 遥感卫星影像数据查询中心-北京揽宇方圆-购买高分卫星影像...
  13. 使用PIL包给图片增加水印
  14. 面试中 项目遇见的难点答案_你和offer之间只差这几个面试问题!常见面试问题汇总...
  15. AirServer2022苹果安卓手机屏幕如何投影到电脑上面
  16. 分布式锁的实现【转载】
  17. 自由曲面光学元件的OAM测量
  18. 图像配准融合(一)——基于互信息的图像配准方法(c++)
  19. 转:Processing 编程学习指南
  20. 求生之路无限子弹服务器,求生之路2怎么调无限子弹(在单机中)

热门文章

  1. 1.多线程-NSThread
  2. 归档—监控ORACLE数据库告警日志
  3. 滴水穿石--Pydoop 架构和模块包介绍
  4. flash与字符串:数组转换为字符串
  5. 优化JavaScript代码
  6. Linux LVM卷挂载
  7. exchange无法收发邮件_Python使用POP3和SMTP协议收发邮件!
  8. MYSQL数据库备份还原,并还原到最新状态(mysqldump,xtrabackup)
  9. Sonar问题解决:普通方法调用静态属性
  10. 联想家庭云中心:天边飘来“故乡的云”