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


思路:
真·树套树
把每棵树所成一个点,然后相当于先把两个点跳到一个块中再求它们的lcalcalca,可以用主席树维护块中编号第kkk大来维护块中对应点,实现块于块之间的跳跃可以用倍增

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){static char buf[rlen],*ib,*ob;(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));return ib==ob?-1:*ib++;
}
typedef long long ll;
inline ll read(){ll ans=0;char ch=gc();while(!isdigit(ch))ch=gc();while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();return ans;
}
const int N=1e5+5;
int rt[N],pred[N],Dep[N],num[N],top[N],hson[N],dep[N],fa[N],siz[N],st[N][20],n,m,q,tot=0;
ll dis[N];
vector<int>e[N];
struct Node{int id;ll l,r,pre;}a[N];
namespace sgt{#define lc son[p][0]#define rc son[p][1]#define mid (l+r>>1)int siz[N*30],son[N*30][2],tot=0;inline void update(int&p,int last,int l,int r,int k){siz[p=++tot]=siz[last]+1,lc=son[last][0],rc=son[last][1];if(l==r)return;k<=mid?update(lc,son[last][0],l,mid,k):update(rc,son[last][1],mid+1,r,k);}inline int query(int pl,int pr,int l,int r,int k){if(l==r)return l;int tmp=siz[son[pr][0]]-siz[son[pl][0]];return tmp>=k?query(son[pl][0],son[pr][0],l,mid,k):query(son[pl][1],son[pr][1],mid+1,r,k-tmp);}#undef lc#undef rc#undef mid
}
void dfs1(int p){siz[p]=1;for(ri i=0,v;i<e[p].size();++i){if((v=e[p][i])==fa[p])continue;fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];if(siz[v]>siz[hson[p]])hson[p]=v;}
}
void dfs2(int p,int tp){top[p]=tp,pred[num[p]=++tot]=p;if(!hson[p])return;dfs2(hson[p],tp);for(ri i=0,v;i<e[p].size();++i)if((v=e[p][i])!=hson[p]&&v!=fa[p])dfs2(v,v);
}
inline int lca(int x,int y){while(top[x]^top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);x=fa[top[x]];}return dep[x]<dep[y]?x:y;
}
inline int find(ll x,int R){int l=1,r=R,ret=R;while(l<=r){int mid=l+r>>1;if(a[mid].r>=x)ret=mid,r=mid-1;else l=mid+1;}return ret;
}
inline ll dist(int blo,int x){return dis[blo]+dep[x]-dep[a[blo].id];}
inline int idx(int blo,ll x){int t=a[blo].id;return sgt::query(rt[num[t]-1],rt[num[t]+siz[t]-1],1,n,x-a[blo].l+1);
}
inline int Lca(int x,int y){if(Dep[x]<Dep[y])swap(x,y);for(ri tmp=Dep[x]-Dep[y],i=19;~i;--i)if((tmp>>i)&1)x=st[x][i];if(x==y)return x;for(ri i=19;~i;--i)if(st[x][i]^st[y][i])x=st[x][i],y=st[y][i];return st[x][0];
}
inline int Find(int x,int k){for(ri i=19;~i;--i)if((k>>i)&1)x=st[x][i];return idx(st[x][0],a[x].pre);
}
inline ll calc(int fx,int fy,int x,int y){int t=Lca(fx,fy);if(fx==t)swap(fx,fy),swap(x,y);if(fy==t){ll ret=dist(fx,x);ret-=dist(t,x=Find(fx,Dep[fx]-Dep[t]-1));return ret+dep[x]+dep[y]-2*dep[lca(x,y)];}ll ret=dist(fx,x)+dist(fy,y);ret-=dist(t,x=Find(fx,Dep[fx]-Dep[t]-1));ret-=dist(t,y=Find(fy,Dep[fy]-Dep[t]-1));return ret+dep[x]+dep[y]-2*dep[lca(x,y)];
}
int main(){n=read(),m=read()+1,q=read();for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);dfs1(1),dfs2(1,1);for(ri i=1;i<=n;++i)sgt::update(rt[i],rt[i-1],1,n,pred[i]);a[1]=(Node){1,1,n,0};ll x,y,Tot=n;for(ri i=2;i<=m;++i){x=read(),y=read();a[i]=(Node){x,Tot+1,Tot+siz[x],y},Tot+=siz[x];st[i][0]=find(y,i-1),Dep[i]=Dep[st[i][0]]+1,dis[i]=dis[st[i][0]]+dep[idx(st[i][0],y)]-dep[a[st[i][0]].id]+1;}for(ri j=1;j<20;++j)for(ri i=1;i<=m;++i)st[i][j]=st[st[i][j-1]][j-1];while(q--){x=read(),y=read();int fx=find(x,m),fy=find(y,m);x=idx(fx,x),y=idx(fy,y);if(fx^fy)cout<<calc(fx,fy,x,y)<<'\n';else cout<<dep[x]+dep[y]-2*dep[lca(x,y)]<<'\n';}
}

转载于:https://www.cnblogs.com/ldxcaicai/p/10633614.html

2019.03.25 bzoj4539: [Hnoi2016]树(主席树+倍增)相关推荐

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

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

  2. Greedy Sequence(2019南京icpc网络预选赛)主席树求区间小于k的最大值

    题意:给出n个整数,构造s1,s2,s3-sn s1,s2,s3-sns1,s2,s3-sn,si sisi满足五个条件 1.s1[i]=i s1[i]=is1[i]=i 2.对于1<j< ...

  3. 牛客网 暑期ACM多校训练营(第一场)J.Different Integers-区间两侧不同数字的个数-离线树状数组 or 可持久化线段树(主席树)...

    J.Different Integers 题意就是给你l,r,问你在区间两侧的[1,l]和[r,n]中,不同数的个数. 两种思路: 1.将数组长度扩大两倍,for(int i=n+1;i<=2* ...

  4. 2020-2021年度第二届全国大学生算法设计与编程挑战赛 (春季赛)- 天才的操作(线段树+主席树+树上倍增)

    题目链接:点击查看 题目分析:刚看到这个题目的时候,口胡了一个假算法,觉得对于每次询问的操作 [l,r][l,r][l,r] ,只需要找到指令集区间 [l,r][l,r][l,r] 内覆盖到点 kkk ...

  5. 模板三连击:树状数组+线段树+主席树

    没事儿干,复习模板...... 1.树状数组 本来不想写这个的,但是反正就几分钟就打完了,所以就写了,水AC数. 洛谷 P3374 [模板]树状数组 1 1 #include<cstdio> ...

  6. 可持久化线段树——主席树

    前言: 最近心(po)血(yu)来(ya)潮(li)学习了一下主席树.(再不学就落伍了) 主席树,即可持久化线段树,支持维护和查询区间的第\(k\)大(小).区间不同种类个数等,基于线段树的思想之上 ...

  7. 【BZOJ4771】七彩树 主席树+树链的并

    [BZOJ4771]七彩树 Description 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j], ...

  8. 2021HDU多校10 - 7084 Pty loves string(KMPnext树+主席树+dfs序)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串 sss,需要回答 qqq 次询问,每次询问给出一对 (x,y)(x,y)(x,y) ,意思是用 sss 的前缀 s[1:x]s[1:x] ...

  9. 洛谷 - P4755 Beautiful Pair(笛卡尔树+主席树)

    题目链接:点击查看 题目大意:给出一个长度为 n 的数列 a,现在一个数对 ( i , j ) 如果满足 a[ i ] * a[ j ] <=max( a[ i ] ~ a[ j ] ),则称其 ...

最新文章

  1. tar命令-压缩,解压缩文件
  2. dataframe常用操作_【Data Mining】机器学习三剑客之Pandas常用算法总结上
  3. python通过pip安装包,提示 pip 不是内部或外部命令
  4. 【机器学习算法专题(蓄力计划)】十六、机器学习中贝叶斯分类算法
  5. mysql 配置文件
  6. Spring 事物传播特性
  7. scratch少儿编程第一季——07、人要衣装佛靠金装——外观模块
  8. 关于GTID模式下备份时 --set-gtid-purged=OFF 参数的实验【转】
  9. 【转】 C++中的new VS C语言中的malloc
  10. php正则匹配sg-nc-wap_PHP正则表达式匹配关键字之外HTML标签a
  11. linux下搭建DNS子域及相关授权详解
  12. 计算机上没有系统软件应用软件也一样能使用,2010判断题一般双击桌面上的程序图标可以打开该程序...
  13. STM8S103系列IO口模拟串口通信(实现真正串口)
  14. 设计模式——终结者模式
  15. ADO的RECORDSET的RECORDCOUNT属性总是为-1
  16. 捕捉百合网的女同志和echarts展示
  17. android edittext过滤空格,关于android:在EditText中拦截空格键的问题
  18. 稀土配合物Ln(DBM)3(Cz-PBM)|Tb(DBM)3(Cz-PBM)|Gd(DBM)3(Cz-PBM)|Ir(L)2(DBM-Ox)Ir(L)2(DBM-Cz)qiyue
  19. 诺基亚财报遭吐槽:被微软收购比摩托罗拉还蠢
  20. 极坐标梯度公式_梯度的极坐标表达式

热门文章

  1. 树莓派与笔记本用远程桌面连接(Xrdp远程桌面服务)
  2. 学校中有老师和学生两类人,而在职研究生既是老师又是学生,对学生的管理和对教师的管理在他们身上都有体现。...
  3. 代码审查清单 Code Review
  4. 集合Collection以及泛型
  5. System.getProperty的用法
  6. MongoDB集群——副本集
  7. 《Unix环境高级编程》读书笔记 第5章-标准I/O流
  8. 谎言被揭露后,你们的时机才会到来!
  9. [工具]将xml文件转换为html显示
  10. python替换UTF-8编码文本中任意特殊字符,包括中文符号问题:大量文本,将其中的特殊字符用空