4539: [Hnoi2016]树

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 746  Solved: 292
[Submit][Status][Discuss]

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

Source

思维难度低,代码难度高。

直接上主席树即可。

代码用时:0.5h。抄一次代码,错误率还是比较低的,只有一个地方接口参数写反了。

 #include<cstdio>
#include<algorithm>
#include<iostream>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,M=;
int n,m,tot,dfn,sm[M],ls[M],rs[M],rt[N],lf[N],rg[N],id[N];
struct P{ int id,rt,fa; ll l,r; }a[N]; template<typename T>inline void rd(T &x){
int t; char ch;
for (t=; !isdigit(ch=getchar()); t=(ch=='-'));
for (x=ch-''; isdigit(ch=getchar()); x=x*+ch-'');
if (t) x=-x;
} void ins(int x,int &y,int L,int R,int k){
y=++tot; sm[y]=sm[x]+;
if (L==R) return; int mid=(L+R)>>;
if (k<=mid) rs[y]=rs[x],ins(ls[x],ls[y],L,mid,k);
else ls[y]=ls[x],ins(rs[x],rs[y],mid+,R,k);
} int que(int k,int z){
int L=,R=n,mid,t,x=rt[lf[k]-],y=rt[rg[k]];
while (L<R){
mid=(L+R)>>; t=sm[ls[y]]-sm[ls[x]];
if (z<=t) R=mid,x=ls[x],y=ls[y];
else L=mid+,z-=t,x=rs[x],y=rs[y];
}
return L;
} int getid(ll x,int ed){
int L=,R=ed+,mid;
while (L+<R){
mid=(L+R)>>;
if (a[mid].l<=x) L=mid; else R=mid;
}
return L;
} struct T{
int tot,fst[N],pnt[N<<],len[N<<],nxt[N<<];
int fa[N],sz[N],son[N],anc[N];
ll d[N];
void add(int x,int y,int z)
{ pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot; } void dfs(int x){
int p; sz[x]=;
for (p=fst[x]; p; p=nxt[p]){
int y=pnt[p];
if (y!=fa[x]){
fa[y]=x; d[y]=d[x]+len[p];
dfs(y); sz[x]+=sz[y];
if (sz[y]>sz[son[x]]) son[x]=y;
}
}
} void nbr(int x,int tp){
lf[x]=rg[x]=++dfn; id[dfn]=x; anc[x]=tp; int p;
if (son[x]) nbr(son[x],tp),rg[x]=rg[son[x]];
for (p=fst[x]; p; p=nxt[p]){
int y=pnt[p];
if (y!=fa[x] && y!=son[x]) nbr(y,y),rg[x]=rg[y];
}
} void div(int x,int tp){
anc[x]=tp; int p;
if (son[x]) div(son[x],tp);
for (p=fst[x]; p; p=nxt[p]){
int y=pnt[p];
if (y!=fa[x] && y!=son[x]) div(y,y);
}
} int lca(int x,int y){
for (; anc[x]!=anc[y]; x=fa[anc[x]])
if (d[anc[x]]<d[anc[y]]) swap(x,y);
return (d[x]<d[y]) ? x : y;
} int gettp(int x,int y){
int z;
for (; anc[x]!=anc[y]; x=fa[anc[x]]) z=anc[x];
return (x==y) ? z : son[y];
} void build(){
rep(i,,n) ins(,n,rt[i-],rt[i],id[i]);
} ll dist(int x,int y){ return d[x]+d[y]-(d[lca(x,y)]<<); }
}t1,t2; int main(){
freopen("bzoj4539.in","r",stdin);
freopen("bzoj4539.out","w",stdout);
rd(n); rd(m); int cas,z; ll x,y;
rd(cas);
rep(i,,n-) rd(x),rd(y),t1.add(x,y,),t1.add(y,x,);
t1.dfs(); t1.nbr(,);
rep(i,,n) ins(rt[i-],rt[i],,n,id[i]);
a[].id=; a[].rt=; a[].l=; a[].r=n;
rep(i,,m){
rd(x); rd(y);
a[i+].rt=x; a[i+].id=i+;
a[i+].l=a[i].r+; a[i+].r=a[i].r+t1.sz[x];
z=getid(y,i); a[i+].fa=y=que(a[z].rt,y-a[z].l+);
t2.add(z,i+,t1.d[y]-t1.d[a[z].rt]+);
}
t2.dfs(); t2.div(,); int u,v,w; ll ans;
while (cas--){
rd(x); rd(y); u=getid(x,m+); v=getid(y,m+); w=t2.lca(u,v);
x=que(a[u].rt,x-a[u].l+); y=que(a[v].rt,y-a[v].l+);
if (u==v) printf("%lld\n",t1.dist(x,y));
else{
if (u==w) swap(u,v),swap(x,y);
if (v==w){
v=t2.gettp(u,w);
ans=t1.d[x]-t1.d[a[u].rt]+t2.d[u]-t2.d[v];
x=a[v].fa; ans+=t1.dist(x,y)+;
}else{
ans=t1.d[x]-t1.d[a[u].rt]+t1.d[y]-t1.d[a[v].rt]+t2.dist(u,v);
u=t2.gettp(u,w); v=t2.gettp(v,w);
x=a[u].fa; y=a[v].fa;
ans-=(t1.d[t1.lca(x,y)]-t1.d[a[w].rt])<<;
}
printf("%lld\n",ans);
}
}
return ;
}

[BZOJ4539][HNOI2016]树(主席树)的更多相关文章

  1. 线段树简单入门 (含普通线段树, zkw线段树, 主席树)

    线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...

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

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

  3. bzoj 4539 [Hnoi2016]树——主席树+倍增

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4539 明明就是把每次复制的一个子树当作一个点,这样能连出一个树的结构,自己竟然都没想到.思维 ...

  4. 【BZOJ3439】Kpm的MC密码 trie树+主席树

    Description 背景 想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的...),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身 ...

  5. 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))

    函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...

  6. HDU5790 Prefix 字典树+主席树

    分析:这个题和spoj的d_query是一个题,那个是求一段区间里有多少个不同的数字,这里是统计有多少个不同的前缀 用字典树进行判重,(和查询不同的数字一样)对于每个不同的前缀,只保留它最后一次出现的 ...

  7. bzoj 3545&&3551: [ONTAK2010]Peaks &&加强版 平衡树&&并查集合并树&&主席树

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Stat ...

  8. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

  9. UOJ#218. 【UNR #1】火车管理 线段树 主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html 题解 如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖.区间求和 ...

随机推荐

  1. HDU 2593 Pirates’ Code (STL容器)

    题目链接 Problem Description Davy Jones has captured another ship and is smiling contently under the sun ...

  2. VueJS 轻松支持 JSX 配置

    使用: babel-preset-vue-app TODO

  3. python基础之内置异常对象

    前言 什么叫异常?简单来说就是程序运行发生了预计结果之外的情况从而导致程序无法正常运行.而python解释器将一些常见的异常情况在它发生时打包成一个异常对象,我们可以通过捕捉这些异常对象从而进行处理, ...

  4. Linux是对用户的密码的复杂度要求设置【转】

    那么Linux是如何实现对用户的密码的复杂度的检查的呢?其实系统对密码的控制是有两部分组成: 1 cracklib 2 /etc/login.defs pam_cracklib.so 才是控制密码复杂 ...

  5. openjudge-NOI 2.6-2985 数字组合

    题目链接:http://noi.openjudge.cn/ch0206/2985/ 题解: 跟背包问题有点相似,暂且算背包型DP吧,虽然是一道递推题…… fj表示和为j时的结果,得: 即为j减去每一个 ...

  6. 002_让你的linux虚拟终端五彩缤纷(1)——LS颜色设置

  7. 基于TCP协议的聊天室控制台版

    我之前写过一篇博客,主要是基于TCP协议实现的聊天室swing版,在此再写一个基于TCP协议实现的聊天室控制台版,便于学习和比较. package 聊天室console版.utils; import ...

  8. javaScript如何跳出多重循环break、continue

    先来说说break和continue之间的区别 for(var i=0;i<10;i++){  if(i>5){  break;  }}console.log(i);  ---6  •当i ...

  9. csu 1503: 点到圆弧的距离

    1503: 点到圆弧的距离 Time Limit: 1 Sec  Memory Limit: 128 MB  Special JudgeSubmit: 614  Solved: 101[Submit] ...

  10. 用JDK自带的监控工具jconsole来监控程序运行

    工具目录:C:\Program Files\Java\jdk1.6.0_06\bin\jconsole.exe 效果如下:监控类ThreadPoolExecutorTest 的运行 选择我们运行的程序 ...