[bzoj] 2851: 极限满月

来源:互联网 发布:淘宝直通车 却没有反应 编辑:程序博客网 时间:2024/05/17 03:06

这道题初看时没想到过树,看了题解才知道可以建虚树

对题目分析可以将b数组想成一颗树,第i个b数组就是点i到根节点的上路径的所有点的集合。

那么在构造树时就相当于将a数组中的所有点取lca ,再将i节点连到lca上,作为lca的儿子。

这样的复杂度是O(nlogn)的。

在询问时离线处理,dfs更新每个点对问题的贡献。

其深度减去lca的深度即为贡献。

#include <cstdio>#include <vector>#include <cstring>using namespace std;const int N=200005;struct node {int len;vector<int> to;}a[N],que[N];int n,m,lca;int fa[N][20];int dep[N];vector <int> son[N];int sig[N];int ans[N];inline int getlca(int x,int y){int p,st=0;if (dep[x]<dep[y]) p=x,x=y,y=p;p=dep[x]-dep[y];while (p){if (p&1) x=fa[x][st];p/=2,st++;}st=0;while (x!=y){if (fa[x][st]!=fa[y][st]||(fa[x][st]==fa[y][st])&&!st){x=fa[x][st];y=fa[y][st];st++;}else st--;}return x;}void dfs(int x){int i;for (i=0;i<que[x].to.size();i++){if (sig[que[x].to[i]]==-1){ans[que[x].to[i]]+=dep[x];sig[que[x].to[i]]=x;}else {ans[que[x].to[i]]+=dep[x]-dep[getlca(x,sig[que[x].to[i]])];sig[que[x].to[i]]=x;}}for (i=0;i<son[x].size();i++) dfs(son[x][i]);}int main(){register int i,j;scanf("%d",&n);int x,st;for (i=1;i<=n;i++){scanf("%d",&a[i].len);for (j=1;j<=a[i].len;j++)scanf("%d",&x),a[i].to.push_back(x);}dep[0]=1;for (i=1;i<=n;i++){if (!a[i].len){fa[i][0]=0;dep[i]=dep[0]+1;son[0].push_back(i);continue;}lca=a[i].to[0];for (j=1;j<a[i].len;j++) lca=getlca(lca,a[i].to[j]);son[lca].push_back(i);dep[i]=dep[lca]+1;st=0;fa[i][st]=lca;while (fa[i][st]) fa[i][st+1]=fa[fa[i][st]][st],st++;}scanf("%d",&m);for (i=1;i<=m;i++){scanf("%d",&que[i].len);for (j=1;j<=que[i].len;j++)scanf("%d",&x),que[x].to.push_back(i);}memset(sig,-1,sizeof(sig));dfs(0);for (i=1;i<=m;i++)printf("%d\n",ans[i]-1);return 0;}


原创粉丝点击