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

如果看不懂可以看一下下面几个博客

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]树的更多相关文章

  1. BZOJ 4539: [Hnoi2016]树 [主席树 lca]

    4539: [Hnoi2016]树 题意:不想写.复制模板树的子树,查询两点间距离. *** 终于有一道会做的题了...... 画一画发现可以把每次复制的子树看成一个大点来建一棵树,两点的lca一定在 ...

  2. 【LG3248】[HNOI2016]树

    [LG3248][HNOI2016]树 题面 洛谷 题解 因为每次你加入的点是原树上某一棵子树 那么我们一次加入一个点,代表一棵子树加到大树下面 那么我们要找到一个点在一个大点中用主席树在\(dfs\ ...

  3. 4539: [Hnoi2016]树

    4539: [Hnoi2016]树 链接 分析: 主席树+倍增. 代码: #include<cstdio> #include<algorithm> #include<cs ...

  4. [BZOJ4539][HNOI2016]树(主席树)

    4539: [Hnoi2016]树 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 746  Solved: 292[Submit][Status][D ...

  5. [HNOI2016]树(可持久化线段树+树上倍增)

    [HNOI2016]树(可持久化线段树+树上倍增) 题面 给出一棵n个点的模板树和大树,根为1,初始的时候大树和模板树相同.接下来操作m次,每次从模板树里取出一棵子树,把它作为新树里节点y的儿子.操作 ...

  6. BZOJ4539: [Hnoi2016]树

    复制的树缩点,主席树查k小,毫无技术含量,纯码农题. #include<bits/stdc++.h> #define u first #define v second #define F ...

  7. bzoj 4539: [Hnoi2016]树

    Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结 点的编号为1,2,-,N,其中结点1为根:我们称这颗树为模板树.小A决定通过 ...

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

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

  9. 洛谷P3248 [HNOI2016]树(主席树 倍增 )

    题意 题目链接 Sol 从上午九点淦到现在qwq 思路比较简单,就是把每次加入的一坨点看成一个,然后直接倍增搞.. 然后慢慢调就可以了... 最后数量级会到达\(10^{10}\),所以应该开long ...

随机推荐

  1. C 连接mysql VC的步骤

    初学C,看到C 连接mysql的教程不是很多,遇到很多的问题,看过许多盟友的解决方法,有点模糊(对我这个菜鸟来说),下面贴出具体步骤,一起学习: 1.C连接mysql的方法:C ,C ++ ,ODBC ...

  2. php 常用数据大全

    一.数组操作的基本函数 数组的键名和值 array_values($arr);获得数组的值 array_keys($arr);获得数组的键名 array_flip($arr);数组中的值与键名互换(如 ...

  3. beta冲刺 用户使用调查报告

    测评结果 一.使用体验 数据加载响应很快,页面切换丝滑流畅. UI有点偏暗,有些字被覆盖了. 页面布局过于居中,两侧空白范围较大. 总体功能完善. 二.登录.注册.忘记密码界面 管理员登录按钮太靠下, ...

  4. Beta 第七天

    今天遇到的困难: 构造新适配器的时候出现了某些崩溃的问题 ListView监听器有部分的Bug 今天完成的任务: 陈甘霖:完成相机调用和图库功能,完成阿尔法项目遗留下来的位置调用问题,实现百度定位 蔡 ...

  5. SDOI2017 相关分析

    把两个式子拆开 Σ(xi-px)(yi-py) =Σ xiyi + py * Σ xi - px * Σ yi + Σ 1* px * py Σ (xi-px)² = Σ xi² +  px * Σ ...

  6. JS 转换数据类型

    JavaScript 是一种动态数据类型语言,变量是没有类型的,可以随机赋予任意值,若变量要转换数据类型,有两种办法:隐式转换和显式转换. 隐式转换可转换为字符串(将一个值加上字符串) 数字(在值的前 ...

  7. slf4j 与 log4j2 基本用法

    简单的说 log4j2 是log4j2的升级版,解决了部分性能问题和部分死锁问题,其使用方式与使用配置与log4j相同. 建议使用maven依赖直接使用log4j2 <dependency> ...

  8. .Net Core SignalR 实时推送信息

    以前一直没用成功过SignalR(.net asp),最近几天又参考了对应的文档,最终调成功啦. 开始之前,应该注意: 一定要.Net Core 2.1.0以上的SDK. VS2017 15.6以上的 ...

  9. Dojo API中文 Dojo内容模块概览,初学者

    官网:http://dojotoolkit.org/reference-guide/1.10/dojo/index.html#dojo-dojo的翻译 dojo 内容: dojo dojo/dojo ...

  10. idea 找不到classpath 为resource下的xml

    注入时不能自动找到在src/main/resources下的xml. @ContextConfiguration(locations = { "classpath:applicationCo ...