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. Could not create pool connection. The DBMS driver exception was: null, message from server: "Host '192.168.XX.XX' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'

    早上打开浏览器准备登陆某个系统,发现Error 404--Not Found,有点奇怪,这个服务器应该没人用了才对,然后到weblogic后台去看日志,报如下错误: "Could not c ...

  2. Alpha阶段报告-hywteam

    一.Alpha版本测试报告 1. 在测试过程中总共发现了多少Bug?每个类别的Bug分别为多少个? BUG名 修复的BUG 不能重现的BUG 非BUG 没能力修复的BUG 下个版本修复 文件路径的表示 ...

  3. 课堂作业 泛型类-Bag

    自定义泛型类Bag 一.具体代码: 代码连接 二.伪代码: 1.思路: 老师讲完后我的想法是要做出一个类似于List的Bag,首先它的本身是又数组构成的并且是可自动增加长度的,然后实现一些基本的操作, ...

  4. Beta冲刺Day7

    项目进展 李明皇 今天解决的进度 部分数据传递和使用逻辑测试 林翔 今天解决的进度 服务器端查看个人发布的action,修改已发布消息状态的action,仍在尝试使用第三方云存储功能保存图片 孙敏铭 ...

  5. OSI七层协议模型、TCP/IP四层模型学习笔记

    1. OSI七层和TCP/IP四层的关系 1.1 OSI引入了服务.接口.协议.分层的概念,TCP/IP借鉴了OSI的这些概念建立TCP/IP模型. 1.2 OSI先有模型,后有协议,先有标准,后进行 ...

  6. 命令行窗口中用telnet测试HTTP协议

    1. 命令行窗口中用telnet测试HTTP协议 HTTP消息是由普通ASCII文本组成.消息包括消息头和数据体部分.消息头以行为单位,每行以CRLF(回车和换行)结束,消息头结束后,额外增加一个CR ...

  7. SourceTree 实现 git flow 流程

    为什么使用 git 和 git flow,这篇文章 深入理解学习Git工作流 的内容相信能够给你一个完整的答案. 我们以使用SVN的工作流来使用git有什么不妥? git 方便的branch在哪里,团 ...

  8. 18-TypeScript模板方法模式

    在有些情况下,一个功能在基础功能上是不会变的,算法的基本骨架也是确定的,但是在某些场景下算法的具体实现有些差异.应对这种问题,可以采用模板方法模式: abstract class Salary{ ab ...

  9. 常用的汇编指令 movs stos

    movsb   把寄存机esi所存的地址的数据以字节复制到edi movsw  把寄存机esi所存的地址的数据以word复制到edi movsd   把寄存机esi所存的地址的数据以dword复制到e ...

  10. MySQL中使用sql语句获得表结构

    最近在研究PHP,那么就必须涉及到mysql.其中一个功能通过表数据自动生成页面,紧接着发现在一张空表中无法读取数据(因为人家刚刚新建,就是空的没有数据) 延伸出来便是直接查表结构获得字段名,再进行处 ...