文章插图
为了提高效率,我们选择边建树边倍增,建树复杂度\(nlogn\) 。
void cone(int a,int b)//cone=conect{ f[a][0]=b; dep[a]=dep[b]+1; add(b,a); for(int i=1;f[f[a][i-1]][i-1];i++) {f[a][i]=f[f[a][i-1]][i-1]; }}int get_lca(int x,int y)//倍增lca{ if(dep[x]<dep[y]) swap(x,y); for(int i=19;i>=0;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i]; if(x==y) return x; for(int i=19;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0];}再考虑回答询问 。
【control 掌控 方法记录】根据我们建树时遵循的求LCA的原则 , 发现每个询问就是求给出所有点到根的并集的节点数 。考虑将所有节点按\(dfn\)排序,则将每个节点与其相邻的节点的LCA加起来就是答案 。
文章插图
void dfs(int now)//求dfn{ dfn[now]=++cnt; for(int i=head[now];i;i=E[i].nex) dfs(E[i].v);}for(int i=1,t;i<=q;i++) {re(t);for(int j=1;j<=t;j++) re(meet[j]);sort(meet+1,meet+t+1,cmp);//按dfn排序int ans=dep[meet[1]];for(int j=2;j<=t;j++) ans+=dep[meet[j]]-dep[get_lca(meet[j],meet[j-1])];printf("%d\n",ans); }完整AC代码
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=200005;template <typename T>inline void re(T &x) { x=0; int f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-f; for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48); x*=f; return;}int n,q;int head[N],totr;struct edge{ int u,v,nex;}E[N<<1];void add(int u,int v){ E[totr++].u=u; E[totr].v=v; E[totr].nex=head[u]; head[u]=totr;}int f[N][20],dfn[N],meet[N],dep[N];void cone(int a,int b)//cone=conect{ f[a][0]=b; dep[a]=dep[b]+1; add(b,a); for(int i=1;f[f[a][i-1]][i-1];i++) {f[a][i]=f[f[a][i-1]][i-1]; }}int get_lca(int x,int y)//倍增lca{ if(dep[x]<dep[y]) swap(x,y); for(int i=19;i>=0;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i]; if(x==y) return x; for(int i=19;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0];}int cnt;void dfs(int now)//求dfn{ dfn[now]=++cnt; for(int i=head[now];i;i=E[i].nex) dfs(E[i].v);}bool cmp(int a,int b){ return dfn[a]<dfn[b];}int main(){ freopen("control.in","r",stdin); freopen("control.out","w",stdout); re(n); for(int i=1,k;i<=n;i++) {re(k);int lca=0;if(k) re(lca);for(int j=1,mana;j<k;j++){re(mana);lca=get_lca(lca,mana);}cone(i,lca); } re(q); dfs(0); for(int i=1,t;i<=q;i++) {re(t);for(int j=1;j<=t;j++) re(meet[j]);sort(meet+1,meet+t+1,cmp);//按dfn排序int ans=dep[meet[1]];for(int j=2;j<=t;j++) ans+=dep[meet[j]]-dep[get_lca(meet[j],meet[j-1])];printf("%d\n",ans); } return 0;}参考
推荐阅读
- n维偏序 方法记录
- ysl1966真假对比_ysl1966真假鉴别方法
- 华为watchgt3怎么测血压_华为watchgt3测血压方法
- 世上用什么方法赚钱最快(大学生赚钱的40个方法)
- 怎么如何快速赚钱(适合在家挣钱方法)
- 如何截图,截图的几种方法(不能截图的app怎么截图)
- 电脑怎么随意截图(电脑六种截图方法)
- 电脑上如何截屏的方法(电脑截屏怎么任意截图)
- iPhone13Pro怎么拍摄动图_拍摄动图方法
- 纪梵希散粉怎么辨别真假_纪梵希散粉辨真假方法