[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
1 4
1 3
4 2
4 5
4 3
3 2
6 9
1 8
5 3
Sample Output
3
3
HINT
经过两次操作后,大树变成了下图所示的形状:
结点6到9之间经过了6条边,所以距离为6;类似地,结点1到8之间经过了3条边;结点5到3之间也经过了3条边。
如果看不懂可以看一下下面几个博客
http://www.cnblogs.com/wfj2048/p/6416591.html
把每一个新添的子树缩成一个点,那么新树就只有m+1点(模板树算一个点)
每一次加树就等于链接新树中两个点
判断y在哪个点用二分,链接的边权为两个点代表的子树根节点的距离
判断这个新点连上的点对应模板树的哪个点,需要判断dfs序区间内的区间第k大,这要用到主席树
查询(x,y)时分清况:先求出(x,y)在模板树的对应点(u,v),新树上的w=LCA(p,q)
1.两个属同一个子树,在模板树求(u,v)距离
2.不属于同一子树(p,q),先求出在新树上的距离,再加上u->u的子树根的距离(模板树),v同理
因为这样算出的距离在w的子树中可能多算,因为路径不一定经过w的根
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<cmath>
- using namespace std;
- typedef long long lol;
- struct ZYYS
- {
- lol rt,id,pre;
- lol l,r;
- }a[];
- lol pos,ch[][],sum[],n,m,root[];
- lol ans;
- struct Tree
- {
- struct Node
- {
- lol next,to;
- lol dis;
- }edge[];
- lol head[],num,dep[],size[],id[],lx[],rx[],top[],cnt,son[],fa[];
- lol d[];
- void add(lol u,lol v,lol dis)
- {
- num++;
- edge[num].next=head[u];
- head[u]=num;
- edge[num].to=v;
- edge[num].dis=dis;
- }
- void dfs1(lol x,lol pa)
- {lol i;
- dep[x]=dep[pa]+;
- size[x]=;
- fa[x]=pa;
- for (i=head[x];i;i=edge[i].next)
- {
- lol v=edge[i].to;
- if (v!=pa)
- {
- d[v]=d[x]+edge[i].dis;
- dfs1(v,x);
- size[x]+=size[v];
- if (size[v]>size[son[x]]) son[x]=v;
- }
- }
- }
- void dfs2(lol x,lol pa,lol tp)
- {lol i;
- lx[x]=++cnt;
- id[cnt]=x;
- top[x]=tp;
- if (son[x])
- {
- dfs2(son[x],x,tp);
- }
- for (i=head[x];i;i=edge[i].next)
- {
- lol v=edge[i].to;
- if (v==pa||v==son[x]) continue;
- dfs2(v,x,v);
- }
- rx[x]=cnt;
- }
- lol gettop(lol x,lol y)
- {lol z;
- while (top[x]!=top[y])
- {
- z=top[x];
- x=fa[top[x]];
- }
- if (x==y) return z;
- return son[y];
- }
- lol lca(lol x,lol y)
- {
- while (top[x]!=top[y])
- {
- if (dep[top[x]]<dep[top[y]]) swap(x,y);
- x=fa[top[x]];
- }
- if (dep[x]>dep[y]) swap(x,y);
- return x;
- }
- lol dist(lol x,lol y)
- {
- return d[x]+d[y]-*d[lca(x,y)];
- }
- }t1,t2;
- lol getid(lol k,lol r)
- {
- lol l=,as=;
- while (l<=r)
- {
- lol mid=(l+r)/;
- if (a[mid].l<=k) as=mid,l=mid+;
- else r=mid-;
- }
- return as;
- }
- void update(lol x,lol &y,lol l,lol r,lol k)
- {
- y=++pos;
- ch[y][]=ch[x][];ch[y][]=ch[x][];
- sum[y]=sum[x]+;
- if (l==r) return;
- lol mid=(l+r)/;
- if (k<=mid) update(ch[x][],ch[y][],l,mid,k);
- else update(ch[x][],ch[y][],mid+,r,k);
- }
- lol query(lol x,lol y,lol l,lol r,lol k)
- {
- if (l==r) return l;
- lol mid=(l+r)/;
- lol zyys=sum[ch[y][]]-sum[ch[x][]];
- if (zyys<k) return query(ch[x][],ch[y][],mid+,r,k-zyys);
- else return query(ch[x][],ch[y][],l,mid,k);
- }
- int main()
- {lol i,Q;
- lol x,y,u,v;
- cin>>n>>m>>Q;
- for (i=;i<=n-;i++)
- {
- scanf("%lld%lld",&u,&v);
- t1.add(u,v,);
- t1.add(v,u,);
- }
- t1.dfs1(,);
- t1.dfs2(,,);
- for (i=;i<=n;i++)
- update(root[i-],root[i],,n,t1.id[i]);
- a[].id=;a[].rt=;a[].l=;a[].r=n;
- for (i=;i<=m;i++)
- {
- scanf("%lld%lld",&x,&y);
- a[i+].id=i+;a[i+].rt=x;
- a[i+].l=a[i].r+;
- a[i+].r=a[i+].l+t1.size[x]-;
- lol z=getid(y,i);
- a[i+].pre=y=query(root[t1.lx[a[z].rt]-],root[t1.rx[a[z].rt]],,n,y-a[z].l+);
- t2.add(z,i+,t1.d[y]-t1.d[a[z].rt]+);
- t2.add(i+,z,t1.d[y]-t1.d[a[z].rt]+);
- }
- t2.dfs1(,);t2.dfs2(,,);
- for (i=;i<=Q;i++)
- {
- scanf("%lld%lld",&x,&y);
- lol p=getid(x,m+),q=getid(y,m+);
- lol w=t2.lca(p,q);
- lol u=query(root[t1.lx[a[p].rt]-],root[t1.rx[a[p].rt]],,n,x-a[p].l+);
- lol v=query(root[t1.lx[a[q].rt]-],root[t1.rx[a[q].rt]],,n,y-a[q].l+);
- if (p==q)
- {
- printf("%lld\n",t1.dist(u,v));
- }
- else
- {
- if (p==w) swap(p,q),swap(u,v);
- if (q==w)
- {
- x=t2.gettop(p,w);
- ans=t2.d[p]-t2.d[x]+t1.d[u]-t1.d[a[p].rt];
- u=a[x].pre;
- ans+=t1.dist(u,v)+;
- }
- else
- {
- ans=(t1.d[u]-t1.d[a[p].rt]+t1.d[v]-t1.d[a[q].rt]);
- ans+=t2.dist(p,q);
- x=t2.gettop(p,w);y=t2.gettop(q,w);
- u=a[x].pre;v=a[y].pre;
- ans+=(t1.d[a[w].rt]-t1.d[t1.lca(u,v)])*;
- }
- printf("%lld\n",ans);
- }
- }
- }
[HNOI2016]树的更多相关文章
- BZOJ 4539: [Hnoi2016]树 [主席树 lca]
4539: [Hnoi2016]树 题意:不想写.复制模板树的子树,查询两点间距离. *** 终于有一道会做的题了...... 画一画发现可以把每次复制的子树看成一个大点来建一棵树,两点的lca一定在 ...
- 【LG3248】[HNOI2016]树
[LG3248][HNOI2016]树 题面 洛谷 题解 因为每次你加入的点是原树上某一棵子树 那么我们一次加入一个点,代表一棵子树加到大树下面 那么我们要找到一个点在一个大点中用主席树在\(dfs\ ...
- 4539: [Hnoi2016]树
4539: [Hnoi2016]树 链接 分析: 主席树+倍增. 代码: #include<cstdio> #include<algorithm> #include<cs ...
- [BZOJ4539][HNOI2016]树(主席树)
4539: [Hnoi2016]树 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 746 Solved: 292[Submit][Status][D ...
- [HNOI2016]树(可持久化线段树+树上倍增)
[HNOI2016]树(可持久化线段树+树上倍增) 题面 给出一棵n个点的模板树和大树,根为1,初始的时候大树和模板树相同.接下来操作m次,每次从模板树里取出一棵子树,把它作为新树里节点y的儿子.操作 ...
- BZOJ4539: [Hnoi2016]树
复制的树缩点,主席树查k小,毫无技术含量,纯码农题. #include<bits/stdc++.h> #define u first #define v second #define F ...
- bzoj 4539: [Hnoi2016]树
Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结 点的编号为1,2,-,N,其中结点1为根:我们称这颗树为模板树.小A决定通过 ...
- 2019.03.25 bzoj4539: [Hnoi2016]树(主席树+倍增)
传送门 题意:给一棵大树,令一棵模板树与这棵树相同,然后进行mmm次操作,每次选择模板树中的一个节点aaa和大树中一个节点bbb,把aaa这棵子树接在bbb上面,节点编号顺序跟aaa中的编号顺序相同. ...
- 洛谷P3248 [HNOI2016]树(主席树 倍增 )
题意 题目链接 Sol 从上午九点淦到现在qwq 思路比较简单,就是把每次加入的一坨点看成一个,然后直接倍增搞.. 然后慢慢调就可以了... 最后数量级会到达\(10^{10}\),所以应该开long ...
随机推荐
- JQuery操作option的添加、删除、取值
1. $("#select_id").change(function(){//code...}); //为Select添加事件,当选择其中一项时触发 2. var checkTex ...
- C语言:第0次作业
问题1: 你为什么选择计算机专业?你认为你的条件如何?和这些博主比呢? 感性地讲,高中时意外看到了电影<社交网络>,自那时起就将将马克扎克伯格视为偶像,他天才的智慧和长远的眼光深深吸引了我 ...
- JAVA接口基础知识总结
1:是用关键字interface定义的. 2:接口中包含的成员,最常见的有全局常量.抽象方法. 注意:接口中的成员都有固定的修饰符. 成员变量:public static final 成员方法 ...
- 一个C&C++程序的生命历程
翻了好多博客,内容星星点点,没找到我想要的,现在吸取大神精华,加上本人拙见,总结如下: 一个C或C++程序从你开始编写,到结束,整个过程,都做了些什么,请看下文: 先看大体的过程:看图: 我在这里主要 ...
- 【基础知识】Flex-弹性布局原来如此简单!!
简言 布局的传统解决方案是基于盒状模型,依赖 display + position + float 方式来实现,灵活性较差.2009年,W3C提出了一种新的方案-Flex,Flex是Flexible ...
- 从PRISM开始学WPF(二)Prism?
目录: 从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WPF(三)Prism-Region? 从PRISM开始学WPF(四)Prism-Modu ...
- EXT3文件系统误删除导致文件系统中的邮件丢失恢复方法
一.故障描述 由8块盘组成的RAID5, 上层是EXT3文件系统,由于误删除导致文件系统中的邮件丢失 二.镜像磁盘为防止数据恢复过程中由于误操作对原始磁盘造成二次破坏, 使用winhex软件为每块磁盘 ...
- Echarts柱状图实现不同颜色渐变色
第一次写文,只是想记录一下自己平时发现的小功能,这篇主要是实现echarts柱状图,每个柱子实现不同颜色的渐变色,也是第一次接触echarts,后台使用ssm,前台是extjs,直接上效果图 直接上j ...
- nyoj 矩形个数
矩形的个数 时间限制:1000 ms | 内存限制:65535 KB 难度:1 描述 在一个3*2的矩形中,可以找到6个1*1的矩形,4个2*1的矩形3个1*2的矩形,2个2*2的矩形,2个3 ...
- docker实践
我的docker 学习笔记2 ps axf docker run -d cyf:sshd /usr/sbin -D docker ps docker-enter.sh 686 ps axf ...