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. 【BZOJ】1901: Zju2112 Dynamic Rankings

    [题意]带修改的查询区间第k小 [算法]树状数组套可持久化线段树 [题解]对于树状数组上的每个节点,维护可持久化权值线段树(节点为权值),从而达到查询前缀和的目的. 对于每次修改,在待修改线段树基础上 ...

  2. 在Windows下安装MongoDB

    概述 读者可以通过本文来学习在Windows操作系统上安装MongoDB. 从2.2版本开始,Mongo DB不在支持Windows XP.请使用最近的windows来安装最近发布的MongoDB.本 ...

  3. CodeForces - 1016B

    You are given two strings ss and tt, both consisting only of lowercase Latin letters. The substring  ...

  4. Python自定义web框架、Jinja2

    WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server ...

  5. npm install ERR! code E400/E404

    在安装webpack的过程中,出现了一个报错npm install ERR! code E400/E404 解决方法: 1.查看npm配置文件 是否有错误: 执行 npm config edit 查看 ...

  6. flask插件系列之flask_celery异步任务神器

    现在继续学习在集成的框架中如何使用celery. 在Flask中使用celery 在Flask中集成celery需要做到两点: 创建celery的实例对象的名字必须是flask应用程序app的名字,否 ...

  7. 使用keytool生成ssl密钥文件keystore和truststore

    最近在研究Mina的开发,通信的时候需要数据加密,而且mina本身支持SSLFilter过滤器,所以可以采用SSL加密的方式对数据进行加密. 在进行加密之前,我们需要使用keytool(这个存在于C: ...

  8. java版云笔记(四)

    页面的笔记本加载完成了,接下来就是点击笔记本显示将笔记显示,同时把笔记在右边的编辑器中,同时把编辑后的笔记更新. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下载,下载地址 ...

  9. mysql 操作时间戳

    1.将long显示成时间 SELECT FROM_UNIXTIME(1249488000, '%Y%m%d' ) 2.日期格式化成时间戳 SELECT UNIX_TIMESTAMP('2016-05- ...

  10. hexdump related.

    hexdump format strings Tue 13 December 2005 In tips. Ian Wienand More from the "things you'd le ...