bzoj 4539 [Hnoi2016]树——主席树+倍增
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4539
明明就是把每次复制的一个子树当作一个点,这样能连出一个树的结构,自己竟然都没想到。思维有待加强。
找编号为 k 的点,可以通过给 dfs 序建立对于编号的主席树。可以做一个 s[ i ] 表示第 i 步操作之后一共有多少个点,二分得知编号第 k 大的点在哪一步操作建出的大点里,然后用主席树查一下具体是哪个小点即可。每个大点记录一下自己的根,还有连向父亲中的哪个小点。
处理出每个小点在原树种的倍增数组和每个大点在新树中的倍增数组,就能查距离了。每个询问用刚才的二分和主席树找到询问的是哪个大点中的哪个小点。
在大点上倍增的时候先别跳最后一步,看看跳了之后是不是在同一个大点里,如果是,直接查询小点之间的距离即可。
数组开 n*17 好像有些不够。 n*20 可以。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls Ls[cr]
#define rs Rs[cr]
#define ll long long
using namespace std;
ll rdn()
{
ll ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=1e5+,K=,M=2e6+;//,M=N*K;
int n,m,Q,hd[N],xnt,to[N<<],nxt[N<<],pre[N][K+],dep[N],siz[N];
int h2[N],xt2,t2[N<<],nt2[N<<],pr2[N][K+],dp2[N];
int tim,dfn[N],rt[N],tot,Ls[M],Rs[M],sm[M];
ll s[N],dis[N][K+]; int bin[K+];
struct Node{
int x,y;
Node(int x=,int y=):x(x),y(y) {}
}a[N];
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void ad2(int x,int y){t2[++xt2]=y;nt2[xt2]=h2[x];h2[x]=xt2;}
void ins(int l,int r,int &cr,int pr,int k)
{
cr=++tot; ls=Ls[pr]; rs=Rs[pr]; sm[cr]=sm[pr]+;
if(l==r)return; int mid=l+r>>;
if(k<=mid)ins(l,mid,ls,Ls[pr],k);
else ins(mid+,r,rs,Rs[pr],k);
}
int qry(int l,int r,int cr,int pr,int k)
{
if(l==r)return l; int mid=l+r>>;
int s=sm[ls]-sm[Ls[pr]];
if(s>=k)return qry(l,mid,ls,Ls[pr],k);
else return qry(mid+,r,rs,Rs[pr],k-s);
}
void ini_dfs(int cr,int fa)
{
siz[cr]=; dep[cr]=dep[fa]+;
dfn[cr]=++tim; ins(,n,rt[tim],rt[tim-],cr);
pre[cr][]=fa;
for(int t=,d;(d=pre[pre[cr][t-]][t-]);t++)
pre[cr][t]=d;
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa) ini_dfs(v,cr),siz[cr]+=siz[v];
}
int Dis(int x,int y)
{
if(!x||!y)return ; int ret=;//
for(int t=K,lm=dep[x];t>=;t--)
if(dep[pre[y][t]]>=lm)
ret+=bin[t], y=pre[y][t];
return ret;
}
void Ini_dfs(int cr,int fa)
{
dp2[cr]=dp2[fa]+; pr2[cr][]=fa;
dis[cr][]=Dis(a[fa].x,a[cr].y)+;
for(int t=,d;pr2[d=pr2[cr][t-]][t-];t++)
{
pr2[cr][t]=pr2[d][t-];
dis[cr][t]=dis[cr][t-]+dis[d][t-];
}
for(int i=h2[cr],v;i;i=nt2[i])
if((v=t2[i])!=fa) Ini_dfs(v,cr);
}
Node fnd(ll k,int r)
{
int l=,bh=;Node ret;
while(l<=r)
{
int mid=l+r>>;
if(s[mid]>=k)bh=mid,r=mid-;
else l=mid+;
}
ret.x=bh; k-=s[bh-]; bh=a[bh].x;
ret.y=qry(,n,rt[dfn[bh]+siz[bh]-],rt[dfn[bh]-],k);
return ret;
}
int Dis2(int x,int y)
{
int ret=;
if(dep[x]!=dep[y])
{
if(dep[x]<dep[y])swap(x,y);
for(int t=K,lm=dep[y];t>=;t--)
if(dep[pre[x][t]]>=lm)
ret+=bin[t], x=pre[x][t];
}
if(x!=y)
{
for(int t=K;t>=;t--)
if(pre[x][t]!=pre[y][t])
{ ret+=bin[t]<<; x=pre[x][t]; y=pre[y][t];}
ret+=;//
}
return ret;
}
int main()
{
n=rdn();m=rdn();Q=rdn(); ll u,v;
for(int i=;i<n;i++)
u=rdn(),v=rdn(),add(u,v),add(v,u);
bin[]=;for(int i=;i<=K;i++)bin[i]=bin[i-]<<;
ini_dfs(,); tot=;s[]=n;a[]=Node(,); m++;
for(int i=;i<=m;i++)
{
u=rdn();v=rdn();s[i]=s[i-]+siz[u];
Node bh=fnd(v,i-); a[i]=Node(u,bh.y);
ad2(i,bh.x); ad2(bh.x,i);
}
Ini_dfs(,);
for(int i=;i<=Q;i++)
{
u=rdn(); v=rdn(); ll ans=;
Node x=fnd(u,m), y=fnd(v,m);//*.x:blk, *.y:point
if(x.x==y.x){printf("%d\n",Dis2(x.y,y.y));continue;}
if(dp2[x.x]!=dp2[y.x])
{
if(dp2[x.x]<dp2[y.x])swap(x,y);
ans+=Dis(a[x.x].x,x.y);
for(int t=K,lm=dp2[y.x]+;t>=;t--)
if(dp2[pr2[x.x][t]]>=lm)
ans+=dis[x.x][t], x.x=pr2[x.x][t];
if(pr2[x.x][]==y.x)
{printf("%lld\n",ans+Dis2(y.y,a[x.x].y)+);continue;}
ans+=dis[x.x][]; x.x=pr2[x.x][]; x.y=a[x.x].x;
}
ans+=Dis(a[y.x].x,y.y); ans+=Dis(a[x.x].x,x.y);
for(int t=K;t>=;t--)
if(pr2[x.x][t]!=pr2[y.x][t])
{
ans+=dis[x.x][t]+dis[y.x][t];
x.x=pr2[x.x][t]; y.x=pr2[y.x][t];
}
printf("%lld\n",ans+Dis2(a[x.x].y,a[y.x].y)+);
}
return ;
}
bzoj 4539 [Hnoi2016]树——主席树+倍增的更多相关文章
- 线段树简单入门 (含普通线段树, zkw线段树, 主席树)
线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...
- BZOJ 4539: [Hnoi2016]树 [主席树 lca]
4539: [Hnoi2016]树 题意:不想写.复制模板树的子树,查询两点间距离. *** 终于有一道会做的题了...... 画一画发现可以把每次复制的子树看成一个大点来建一棵树,两点的lca一定在 ...
- bzoj 4539: [Hnoi2016]树
Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结 点的编号为1,2,-,N,其中结点1为根:我们称这颗树为模板树.小A决定通过 ...
- [BZOJ4539][HNOI2016]树(主席树)
4539: [Hnoi2016]树 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 746 Solved: 292[Submit][Status][D ...
- bzoj 3545&&3551: [ONTAK2010]Peaks &&加强版 平衡树&&并查集合并树&&主席树
3545: [ONTAK2010]Peaks Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 635 Solved: 177[Submit][Stat ...
- Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...
- BZOJ 4556(后缀数组+主席树求前驱后继+二分||后缀数组+二分+可持久化线段树)
换markdown写了.. 题意: 给你一个1e5的字符串,1e5组询问,求\([l_1,r_1]\)的所有子串与\([l_2,r_2]\)的lcp 思路: 首先可以发现答案是具有单调性的,我们考虑二 ...
- BZOJ 3524: [Poi2014]Couriers [主席树]
3524: [Poi2014]Couriers Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1892 Solved: 683[Submit][St ...
- bzoj 4012: [HNOI2015]开店 主席树
Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...
随机推荐
- drawImage
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head> < ...
- 清除mac出现的.DS_Store文件
一.什么是.DS_Store文件 在 Mac OS X 系统下,大部分文件夹中都包含 .DS_Store 隐藏文件,这里保存着针对这个目录的特殊信息和设置配置,例如查看方式.图标大小以及这个目录的一些 ...
- js设计模式-观察者模式
定义: 观察者模式又叫发布订阅模式,它定义了对象间的一种一对多的依赖关系.观察者模式让两个对象松耦合地联系在一起,虽然不太清楚彼此的细节,但这不影响他们之间的互相通信. 思路 定义一个对象,在对象中实 ...
- POJ 2513 字典树+并查集+欧拉路径
Description: 给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的. 解题思路: 可以用图论中欧拉路的知识来解这道题,首先可以把木 ...
- httpclient httpclient连接回收
httpclient连接释放 httpClient必须releaseConnection,但不是abort.因为releaseconnection是归还连接到到连接池,而abort是直接抛弃这个连接, ...
- css控制编辑器内容自动换行
在编辑器或者文本框中按住数字或字母不放 当字符很长时,就会撑破页面, 可以用一下方法控制字符自动换行 style="word-break:break-all;"
- bacula配置
Bacula Bacula是一款开源的跨平台网络备份工具,提供基于企业级的CS的备份解决方案.可以对数据进行备份.恢复.以及完整性校验. 功能特点: 支持完全备份,增量备份,差异备份. 支持多种恢复 ...
- 官网下载的spring-framework的一些描述
刚下载下来是这个文件夹:
- linux 优化git操作速度
修改 ssh配置:useDNS:no
- 配置动态加载模块和js分模块打包,生产环境和开发环境公共常量配置
1. 话不多少 先上代码: route.js // 引用模板 分模块编译 const main = r => require.ensure([], () => r(require('. ...