题目链接:https://loj.ac/problem/6184
每次询问给一些关键点,询问树上每个点离最近的关键点的距离(以后称为f(u))最大值是多少。
询问数比较大,但 \sum{K} 和n是一个级别的,我们考虑每次把询问的点建成虚树,在虚树上统计答案。那些不在虚树上的点的一定是通过虚树上的点走到的,它们的f(u)也都是通过虚树上的信息来维护的。
(update 7.17)建虚树的过程具体就是在栈中保存一条还未进行连边构图的树链,先按dfn序从小到大排序,如果新加入的点恰好是栈顶的后辈就直接把它加入栈中,如果不是就记他们的lca为u,我们只需要找到u从下到上第一个在栈中出现的祖先,并让它在top-1的位置,其他弹掉并建边即可。这是因为按dfn排过序,这时u->原栈顶 这条树链不可能再有新的分叉了,所以我们没必要保存它们,直接建边弹出栈就好了,而u以上的树链并不确定,我们还不能弹掉。至于弹后的栈顶,我们根据它是否是u来判断是否将u加入栈。做完上述操作后再将新节点加进去就没毛病了。

细节较多的分类讨论:

1、一个虚树上的节点的其他不在虚树中的子树中的答案,由于要排除掉在虚树上(或虚树边上)的儿子,需要预处理的时候对每个点开个有序的vector记录每个儿子子树最深值,查询时找到第一个不在虚树(边)上的儿子就break,这样统计这部分答案的均摊代价是O(虚树度数)的。
2、一条虚树上压缩后的长度大于1的边上的点的不在虚树中的子树中的答案。这部分我们需要通过预处理的倍增数组O(log(n))地来找到从上面的节点u走最优或从下面的节点v走最优的分界点k。然后d---k询问从d走到d->k中的一个点再往不包含d的子树中走的最大值,k->u询问u向下走不经过k的子树最大值。这两个东西都可以预先用倍增数组求出来,单次查询O(log2(n))。

注意:

1、最好强制让1是虚树的根,否则最后还得考虑虚树的根往上走再折回来的答案。
2、别忘了答案仍可能出在虚树上,要把虚树上节点的f值取个max。
接下来是一份AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(register int i=(a);i<=(b);++i)
typedef long long ll;
const int N = 200005;
int n,Q,nn;
struct la{int gr,h[N],nxt[N],to[N],w[N];inline void tu(int x,int y,int c=0){to[++gr]=y,nxt[gr]=h[x],h[x]=gr,w[gr]=c;}
}R,F;int K[N],cnt,tim,dfn[N];
int ff[N][24],m,dep[N],zhe[N][24],dwn[N][24];
int sta[N],top,f[N],g[N],bit[N];
vector<int> son[N];
bool cmp2(const int &a,const int &b){return f[a]>f[b];}
void dfs(int u,int fa){dfn[u]=++tim;dep[u]=dep[fa]+1;ff[u][0]=fa;rep(i,1,m){ff[u][i]=ff[ff[u][i-1]][i-1];if(!ff[u][i])break;}for(int i=R.h[u];i;i=R.nxt[i]){int d=R.to[i];if(d==fa)continue;dfs(d,u);if(f[d]+1>f[u])g[u]=f[u],f[u]=f[d]+1;else g[u]=max(g[u],f[d]+1);son[u].push_back(d);}if(son[u].size()>0)sort(son[u].begin(),son[u].end(),cmp2);for(int i=R.h[u];i;i=R.nxt[i]){int d=R.to[i];if(d==fa)continue;zhe[d][0]=(son[u][0]==d?g[u]:f[u])+1;dwn[d][0]=(son[u][0]==d?g[u]:f[u]);}}
void beizeng(){rep(i,1,m){rep(u,1,n){if(!ff[u][i])continue;zhe[u][i]=max(zhe[ff[u][i-1]][i-1]+bit[i-1],zhe[u][i-1]);dwn[u][i]=max(dwn[ff[u][i-1]][i-1],dwn[u][i-1]+bit[i-1]);}}
}
inline int lca(int x,int y){if(dep[x]<dep[y])swap(x,y);for(int i=m;i>=0;--i)if(dep[ff[x][i]]>=dep[y])x=ff[x][i];if(x==y)return x;for(int i=m;i>=0;--i)if(ff[x][i]!=ff[y][i])x=ff[x][i],y=ff[y][i];return ff[x][0];
}
bool cmp(int x,int y){return dfn[x]<dfn[y];}
int dis[N],ans;
bool is[N],in[N];
void dp_up(int u){if(is[u])dis[u]=0;else dis[u]=0x3f3f3f3f;for(int i=F.h[u];i;i=F.nxt[i]){int d=F.to[i];dp_up(d);dis[u]=min(dis[u],dis[d]+F.w[i]);}
}
int btw(int u,int d){for(int i=0;i<=m;++i)if(d&bit[i])u=ff[u][i];return u;
}
void get_up(int u,int d,int k){if(!d)return;int t=0;for(int i=0;i<=m;++i)if(d&bit[i]){ans=max(ans,t+k+zhe[u][i]);u=ff[u][i],t+=bit[i];}}
void get_dwn(int u,int d,int k){if(d<=0)return;for(int i=0;i<=m;++i)if(d&bit[i]){d-=bit[i],ans=max(ans,k+d+dwn[u][i]);u=ff[u][i];if(!d)return;}
}
int que[N],r;
void dp_dwn(int u){int tmp=0,now;ans=max(ans,dis[u]);//printf("%d %d\n",u,dis[u]);for(int i=F.h[u];i;i=F.nxt[i]){int d=F.to[i];dis[d]=min(dis[d],dis[u]+F.w[i]);dp_dwn(d);tmp=(dis[u]-dis[d]+F.w[i])/2;if(F.w[i]>1){if(tmp==F.w[i])get_up(d,tmp-1,dis[d]);else if(tmp==0)get_dwn(d,F.w[i]-1,1+dis[u]);else{now=btw(d,tmp);get_up(d,tmp,dis[d]);get_dwn(now,F.w[i]-tmp-1,dis[u]+1);}now=btw(d,F.w[i]-1);in[now]=1;que[++r]=now;}}
}
void get_son(int u){rep(i,0,(int)(son[u].size()-1)){if(!in[son[u][i]]){ans=max(ans,dis[u]+f[son[u][i]]+1);break;}}for(int i=F.h[u];i;i=F.nxt[i]){int d=F.to[i];get_son(d);}F.h[u]=0;in[u]=0;
}
int main(){freopen("inception.in","r",stdin);freopen("inception.out","w",stdout);scanf("%d%d",&n,&Q);m=log2(n);int u,v;rep(i,2,n)scanf("%d%d",&u,&v),R.tu(u,v),R.tu(v,u);bit[0]=1;rep(i,1,m)bit[i]=bit[i-1]<<1;dfs(1,0);beizeng();while(Q--){scanf("%d",&cnt);rep(i,1,cnt)scanf("%d",&K[i]),is[K[i]]=1;sort(K+1,K+cnt+1,cmp);F.gr=0;ans=0;sta[top=1]=1;//默认让1来做虚树的根,会省去一些麻烦in[1]=1;rep(i,1,cnt){if(K[i]==1)continue;int tmp=lca(sta[top],K[i]);in[K[i]]=1;if(tmp==sta[top]){sta[++top]=K[i];continue;}while(top>1&&dfn[sta[top-1]]>=dfn[tmp]){F.tu(sta[top-1],sta[top],dep[sta[top]]-dep[sta[top-1]]);top--;}if(sta[top]!=tmp)F.tu(tmp,sta[top],dep[sta[top]]-dep[tmp]),sta[top]=tmp,in[tmp]=1;sta[++top]=K[i];}while(top>1)F.tu(sta[top-1],sta[top],dep[sta[top]]-dep[sta[top-1]]),top--;dp_up(1);dp_dwn(1);get_son(1);printf("%d\n",ans);//clear_is,grrep(i,1,cnt)is[K[i]]=0;rep(i,1,r)in[que[i]]=0;r=0;}return 0;
}

转载于:https://www.cnblogs.com/Sinuok/p/11039319.html

【loj6184】无心行挽(虚树+倍增)相关推荐

  1. loj 6184 无心行挽 虚树+DP+倍增

    题目分析 首先,这题肯定要用虚树. 接下来,你会发现,使得f(u)f(u)f(u)最大的uuu,可能存在于三个位置: 虚树上 虚树上一个没有关键点的子树中 虚树上的一条边中 于是便分类讨论. 对于第一 ...

  2. P3233-[HNOI2014]世界树【虚树,倍增】

    正题 题目链接:https://www.luogu.com.cn/problem/P3233 题目大意 nnn个点的一棵树,mmm次选出一些点作为关键点.每个树上的点会对最近的关键点做贡献,求每个关键 ...

  3. UOJ#271. 【清华集训2016】连通子树(虚树+倍增)

    传送门 题解: 注意到每种颜色个数比较少,于是建出虚树后暴力背包,用倍增维护一下虚链上的DP值即可. 所以说你只需要5个倍增数组和一些卡常技巧加上无数的小细节就可以通过这道题了. 不说了我去睡觉了. ...

  4. 【Codeforces613D】Kingdom and its Cities【虚树】【Tree DP】倍增lca

    http://codeforces.com/problemset/problem/613/D 题意: 给出n个点的树,有q个询问,每次询问给出k个重要的点,问至少删掉多少个非重要的点,使得这个重要的点 ...

  5. [HNOI2014]世界树 (虚树DP+倍增)

    世界树 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石 ...

  6. 虚树(bzoj 3572: [Hnoi2014]世界树)

    例题: 一棵n个节点的树,m次查询,每次查询给你一个点集U,对于树上的所有节点x(x∉U),你要找到一个点y(y∈U)满足y点离x点最近且标号最小,表示x点受y点管辖,而你的任务就是对于每次查询输出U ...

  7. bzoj 3572 [Hnoi2014]世界树——虚树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3572 关于虚树:https://www.cnblogs.com/zzqsblog/p/556 ...

  8. luogu3233 世界树 (虚树)

    反正肯定要建虚树,考虑建完之后怎么做 先随便dp一下算出来距离某点最近的询问点mi[x](因为有的虚树上的点它不是询问点嘛) 那我们对于某条链x到fa[x]上的非虚树上的点(包括他们的非虚树上的孩子) ...

  9. BZOJ3572 [Hnoi2014]世界树 【虚树 + 树形dp】

    题目 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石. ...

  10. 牛客 - 王国(虚树+树的直径)

    题目链接:点击查看 题目大意:给出 n 个点组成的一棵树,每个节点都有一个权值,现在规定权值相同的节点之间,简单路径的边数为 x ,求 x * x 的最大值 题目分析:真的很巧,上周刚学的虚树,读完这 ...

最新文章

  1. 三阶魔方还原步骤图_(六)最简单的三阶魔方入门教程——顶面还原
  2. shaderlab学习一
  3. 手持机连不上信道设置为13的AP
  4. Summation Order
  5. 怎么样用idea上传git?-通俗易懂
  6. pythonexcel表格教程_python对excel表格的操作
  7. canvas中文显示乱码 html5_浅析HTML5 Canvas的几种中文字体缩小方案
  8. 肝!一款基于 Python 语言的 Linux 资源监视器!
  9. 基于Eclipse搭建STM32开源开发环境
  10. JavaScript——使用对话框
  11. vue写自定义指令(全局或者组件内部)
  12. splice删除选中列表_JS之删除数组中的元素的方法如delete和splice
  13. 线性代数中(线代中)的克莱姆法则,又译克拉默法则(Cramer‘s Rule)
  14. 『市场基础变量计算』
  15. 【Verilog基础】数字电路-逻辑式化简公式(附吸收律推导过程)
  16. C++Qt入门(1)---Qt简介,第一个Qt程序,Qt按钮
  17. 计算器(Java)课设
  18. html5播放推流播放地址是黑屏的,OBS Studio直播推流显示黑屏怎么办?教你解决方法...
  19. 多波束测深系统工作原理及组成,多波束在无人船上的应用
  20. Revit二次开发之按照标高过滤元素

热门文章

  1. FreeIPA问题记录
  2. 应届生实习需要注意哪些方面?
  3. QT文本编辑器(QMainwindow版)超详细
  4. iWebShop核心团队启动shukai新域名,进入全案SEO网络营销领域发力SEO众包外包服务
  5. java 生成纯色图片_浅谈Java设置PPT幻灯片背景——纯色、渐变、图片背景
  6. jar包打开闪退解决办法
  7. 百度推广怎么做排名靠前网站链接
  8. 【IoT】创业:产品雷达图 - 如何明智地权衡产品?
  9. Canvas: trying to draw too large bitmap 红米 k30 奔溃
  10. 多个视频ts文件合并