题意:

给你一棵有n个节点的树,树的边权都是1.

有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值。

思路:

1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_dis[i],维护非子树节点中距离该点的最大值fa_dis[i];

2.对于每个节点维护它最大的三个儿子节点的son_dis;

3.维护up[i][j]和down[i][j]数组,这个类似倍增lca里边的fa[i][j],up[i][j]代表的含义是从第j个点向上到它的第2^i个父节点这条链上的点除了该节点所在子树外的距离的最大值。down[i][j]同理,但是维护的是从第2^i父节点到该点的链上除了该节点所在子树外的距离的最大值。在这里尤其注意的是,采取了类似差分的思想。看巨巨代码的时候我想了好一会。到这里预处理完毕。

4.对于给定的两个节点。假设a为深度较深的,b为深度浅的。

对于节点a,a到a的子树中所有的点肯定较近,所以son_dis[a]有可能是答案。a到a和b的中点的那条链上距离的最大值也有可能是答案。

对于b

假设b不是公共祖先,那么son_dis[b]有可能是答案。b到中点的链上的距离的最大值也有可能是答案。

若b是公共祖先,那么只有b到中点的链上的距离的最大值也有可能是答案。

对于最近公共祖先r

r的不包含a和b的子树的dis_son有可能是答案,r的fa_dis[r]有可能是答案。

最终结果是在有可能的答案中找最大值。

代码越改越挫。

#include<bits/stdc++.h>
#define MAXN 100050
#define MAXM 200050
using namespace std;
const int inf=0x3f3f3f3f;
struct st{
int num,id;
};
bool operator < (const st &a,const st &b){
return a.num>b.num;
}
multiset<st>my_set[MAXN];
struct edge{
int id;
edge *next;
};
int ednum;
edge edges[MAXM];
edge *adj[MAXN];
int dep[MAXN],son_dis[MAXN],fa_dis[MAXN],max_num[MAXN],father[MAXN],max_x[MAXN],rt[][MAXN],siz[MAXN],up[][MAXN],down[][MAXN];
bool vis[MAXN];
inline void addedge(int a,int b){
edge *tmp=&edges[ednum++];
tmp->id=b;
tmp->next=adj[a];
adj[a]=tmp;
}
void dfs(int pos,int deep){
dep[pos]=deep;
siz[pos]=;
int mmax=-;
for(edge *it=adj[pos];it;it=it->next){
if(dep[it->id]==){
father[it->id]=pos;
rt[][it->id]=pos;
dfs(it->id,deep+);
st tmp;
tmp.id=it->id;
tmp.num=son_dis[it->id];
my_set[pos].insert(tmp);
mmax=max(mmax,son_dis[it->id]);
son_dis[pos]=max(son_dis[pos],son_dis[it->id]+);
siz[pos]+=siz[it->id];
}
}
int num=;
for(edge *it=adj[pos];it;it=it->next){
if(father[it->id]==pos&&son_dis[it->id]==mmax)num++;
}
max_num[pos]=num;
max_x[pos]=mmax+;
}
void dfs2(int pos){
fa_dis[pos]=fa_dis[father[pos]]+;
if(max_num[father[pos]]>||son_dis[pos]+!=max_x[father[pos]]){
fa_dis[pos]=max(fa_dis[pos],max_x[father[pos]]+);
up[][pos]=max_x[father[pos]]-dep[father[pos]];
down[][pos]=max_x[father[pos]]+dep[father[pos]];
}
else{
int maxx=-;
for(edge *it=adj[father[pos]];it;it=it->next){
if(father[it->id]==father[pos]&&(it->id!=pos)){
maxx=max(maxx,son_dis[it->id]);
}
}
fa_dis[pos]=max(fa_dis[pos],maxx+);
if(maxx==-)maxx=-;
maxx++;
up[][pos]=maxx-dep[father[pos]];
down[][pos]=maxx+dep[father[pos]];
}
for(edge *it=adj[pos];it;it=it->next){
if(father[it->id]==pos)dfs2(it->id);
}
}
void prelca(int n){
up[][]=down[][]=-inf;
for(int i=;i<=;i++){
for(int j=;j<=n;j++){
rt[i][j]=rt[i-][j]==-?-:rt[i-][rt[i-][j]];
up[i][j]=max(up[i-][j],up[i-][rt[i-][j]]);
down[i][j]=max(down[i-][j],down[i-][rt[i-][j]]);
}
}
}
int LCA(int u,int v){//查询u和v的lca
if(dep[u]<dep[v])swap(u,v);
for(int i=;i<;i++){
if((dep[u]-dep[v])>>i&){
u=rt[i][u];
}
}
if(u==v)return u;
for(int i=;i>=;i--){
if(rt[i][u]!=rt[i][v]){
u=rt[i][u];
v=rt[i][v];
}
}
return rt[][u];
}
int jump(int &pos,int num,int tmp[][MAXN]){//查询节点pos的第num个父亲
int rel=-inf;
for(int i=;i<;i++){
if(num>>i&){
rel=max(rel,tmp[i][pos]);
pos=rt[i][pos];
}
}
return rel;
}
void solve(int a,int b){
int r=LCA(a,b);
if(dep[a]<dep[b])swap(a,b);
int maxa,maxb,maxc,maxd,half,v,w,ar,br;
maxa=maxb=maxc=maxd=;
ar=dep[a]-dep[r];
br=dep[b]-dep[r];
v=a;w=b;
half=min((ar+br)/,ar-);
maxa=max(son_dis[a],jump(v,half,up)+dep[a]);
maxb=jump(v,ar-half-,down)-dep[r]+br;
maxc=-inf;
maxd=fa_dis[r]+min(ar,br);
if(r!=b){
maxb=max(maxb,son_dis[b]);
maxb=max(maxb,jump(w,br-,up)+dep[b]);
set<st>::const_iterator it=my_set[r].begin();
for(int i=;i<=min((int)my_set[r].size(),);i++){
if(it->id!=v&&it->id!=w){
maxc=it->num++min(dep[a],dep[b])-dep[r];
break;
}
it++;
}
}
else{
set<st>::const_iterator it=my_set[r].begin();
for(int i=;i<=min((int)my_set[r].size(),);i++){
if(it->id!=v){
maxc=it->num+;
break;
}
it++;
}
}
printf("%d\n",max(max(maxa,maxb),max(maxc,maxd)));
}
int main(){
int n;
scanf("%d",&n);
for(int i=;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
int m;
memset(rt,-,sizeof(rt));
dfs(,);
for(edge *it=adj[];it;it=it->next){
if(father[it->id]==){
dfs2(it->id);
}
}
prelca(n);
scanf("%d",&m);
for(int i=;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
solve(a,b);
}
}

Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]的更多相关文章

  1. @codeforces - 418D@ Big Problems for Organizers

    目录 @description@ @solution@ @accepted code@ @details@ @description@ n 个点连成一棵树,经过每条边需要花费 1 个单位时间. 现给出 ...

  2. hdu5449 Robot Dog (树形dp+倍增lca)

    (警告:本篇博客包含大量人类本质内容) 先处理出来lca,然后就只需要知道从每个点到他的父亲.和从他的父亲到这个点的期望时间就可以了 我们设f[x]为x到他父亲的期望时间:g[x]为从x的父亲到x的期 ...

  3. 【bzoj2500】幸福的道路 树形dp+倍增RMQ+二分

    原文地址:http://www.cnblogs.com/GXZlegend/p/6825389.html 题目描述 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一 ...

  4. Codeforces 219D - Choosing Capital for Treeland(树形dp)

    http://codeforces.com/problemset/problem/219/D 题意 给一颗树但边是单向边,求至少旋转多少条单向边的方向,可以使得树上有一点可以到达树上任意一点,若有多个 ...

  5. codeforces 633F The Chocolate Spree (树形dp)

    题目链接:http://codeforces.com/problemset/problem/633/F 题解:看起来很像是树形dp其实就是单纯的树上递归,就是挺难想到的. 显然要求最优解肯定是取最大的 ...

  6. codeforces 486 D. Valid Sets(树形dp)

    题目链接:http://codeforces.com/contest/486/problem/D 题意:给出n个点,还有n-1条边的信息,问这些点共能构成几棵满足要求的树,构成树的条件是. 1)首先这 ...

  7. Codeforces 671D. Roads in Yusland(树形DP+线段树)

    调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果 ...

  8. CodeForces 816E Karen and Supermarket ——(树形DP)

    题意:有n件商品,每件商品都最多只能被买一次,且有一个原价和一个如果使用优惠券以后可以减少的价格,同时,除了第一件商品以外每件商品都有一个xi属性,表示买这个商品时如果要使用优惠券必须已经使用了xi的 ...

  9. CodeForces 219D Choosing Capital for Treeland (树形DP)经典

    <题目链接> 题目大意: 给定一个有向树,现在要你从这颗树上选一个点,使得从这个点出发,到达树上其它所有点所需翻转的边数最小,输出最少需要翻转的边数,并且将这些符合条件的点输出. 解题分析 ...

随机推荐

  1. php 开启COM组件

    1.先到PHP.INI中打开COM选项,com.allow_dcom = true 2.我这里的环境是PHP5.4.7,PHP 5.4.5后,com/dotnet 模块已经成了单独的扩展,所以需要在P ...

  2. C# toString()转换详细(转)

    文章转自:http://blog.csdn.net/xiaoguang44/article/details/6988418 字符型转换为字符串 // C 货币 2.5.ToString("C ...

  3. 搭建EF6.0+MVC4搭建框架——之路由配置

    为了适应项目需求,需要将前后台的控制器和视图等文件分开,便于修改和维护: 方案一:在原有的Controller下新增Admins文件夹用于放置后台控制器文件: 控制器文件目录如下图: 视图文件目录:

  4. JSP页面中<%! %>和<% %>的区别

    JSP声明语句:<%!声明语句%>,通常声明全局变量.常量.方法.类JSP Scriptlet:<%java代码%>,其中可包含局部变量.java语句JSP表达式:<%= ...

  5. 延迟加载、异步加载js

    defer为true:延迟加载脚本,在文档完成解析完成开始执行,并且在DOMContentLoaded事件之前执行完成. async(HTML5新增的属性)为true:异步加载脚本,下载完毕后再执行, ...

  6. Oracle 支持正则表达式的函数

    内容提要 oracle 10g 增加的正则表达式函数有以下四种: regexp_like() --返回满足条件的字段 regexp_instr() --返回满足条件的字符或字符串的位置 regexp_ ...

  7. jsonp get 和 post

    原文地址:http://blog.sina.com.cn/s/blog_4a7e719d0100zqzh.html jsonp获取服务器的数据,有两种一,跨域二,不跨域如果跨域js的写法有两种1,&l ...

  8. Linux下编译Boost

    编译环境 操作系统: Red Hat Enterprise Linux Server release 5.4 64-bit 编译工具: gcc (GCC) 4.1.2 20080704 (Red Ha ...

  9. DB设计原则(一)字段名定义避免二义性。

    字段名定义避免二义性.如:主数据中有库存信息表 KCDDID,KCDDMC.若要在业务表中存储库存地点ID的话,不要定义为KCDD,要定义为KCDDID.这样标明存储的就是ID,而不是名称.同样,单位 ...

  10. windows7使用Source insight上远程修改ubuntu共享内核源码

    由于本人阅读喜欢使用source insight.前段时间接触了linux核代码,而这份代码只能放在ubuntu服务器上编译,刚开始的时候是在windows上修改,完了之后再copy到服务器上去编译, ...