题意:给出一棵树,1为根节点,求一段区间内所有点的最近公共祖先。

解法:用一棵线段树维护区间LCA。LCA是dp做法。dp[i][j]表示点i的第2^j个祖先是谁,转移方程为dp[i][j] = dp[dp[i][j - 1]][j - 1],初始的dp[i][0]可以用一次dfs求得,这样可以用logn的时间求第x个祖先或查询LCA。求第x个祖先可以从二进制的角度理解,假设x是10,转化为二进制是1010,那么只要升2^3 + 2^1个深度就可以求出第x个祖先。求LCA的具体做法是,先将点a和b升至同一深度,如果此时a和b为同一个点,说明LCA就是a(或者b),如果不是同一个点,再同时向上升,直到已经无法找到两个点的祖先是不同点,说明两个点已经升至LCA的下一层,再向上升一层即为LCA。

然后就是建一棵线段树,只需要查询,没有更新,查询的写法纠结了好久……

因为代码写的太屎了,扩栈了依然会RE……所以只好用栈模拟……但是不扩栈又会T……不太理解那句扩栈用的语句的原理TUT……5000+ms擦边过了……

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define LL long long
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:10240000000,10240000000")
using namespace std;
vector <int> tree[300005];
bool vis[300005];
int deep[300005];
int dp[300005][30];
int st[300005 << 2];
struct node
{
int rt, dep;
node(int rt, int dep) : rt(rt), dep(dep) {}
node() {}
};
stack <node> s;
int LCA(int a, int b)
{
if(deep[a] < deep[b])
swap(a, b);
for(int i = 20; i >= 0; i--)
{
if(deep[a] == deep[b])
break;
if(deep[dp[a][i]] >= deep[b])
a = dp[a][i];
}
if(a == b)
return a;
for(int i = 20; i >= 0; i--)
{
if(dp[a][i] != dp[b][i])
{
a = dp[a][i];
b = dp[b][i];
}
}
return dp[a][0];
}
void pushUp(int rt)
{
st[rt] = LCA(st[rt << 1], st[rt << 1 | 1]);
}
void build(int l, int r, int rt)
{
if(l == r)
{
st[rt] = l;
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushUp(rt);
}
int query(int ll, int rr, int l, int r, int rt)
{
if(ll <= l && rr >= r)
return st[rt];
int m = (l + r) >> 1;
int res;
if(ll <= m)
{
res = query(ll, rr, lson);
if(rr > m)
return LCA(res, query(ll, rr, rson));
else
return res;
}
else
return query(ll, rr, rson);
}
int main()
{
int n;
while(~scanf("%d", &n))
{
for(int i = 0; i < 300005; i++)
tree[i].clear();
for(int i = 0; i < n - 1; i++)
{
int a, b;
scanf("%d%d", &a, &b);
tree[a].push_back(b);
tree[b].push_back(a);
}
memset(vis, 0, sizeof vis);
memset(dp, 0, sizeof dp);
vis[1] = true;
dp[1][0] = 1;
s.push(node(1, 1));
while(!s.empty())
{
node top = s.top();
deep[top.rt] = top.dep;
int len = tree[top.rt].size();
int flag = true;
for(int i = 0; i < len; i++)
{
if(!vis[tree[top.rt][i]])
{
vis[tree[top.rt][i]] = true;
dp[tree[top.rt][i]][0] = top.rt;
s.push(node(tree[top.rt][i], top.dep + 1));
flag = false;
}
}
if(flag)
s.pop();
}
for(int j = 1; j < 20; j++)
{
for(int i = 1; i <= n; i++)
{
dp[i][j] = dp[dp[i][j - 1]][j - 1];
}
}
build(1, n, 1);
int q;
scanf("%d", &q);
for(int i = 0; i < q; i++)
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", query(a, b, 1, n, 1));
}
}
return 0;
}

  

HDU 5266 pog loves szh III的更多相关文章

  1. hdu 5266 pog loves szh III(lca + 线段树)

    I - pog loves szh III Time Limit:6000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I ...

  2. HDU 5266 pog loves szh III(区间LCA)

    题目链接 pog loves szh III 题意就是  求一个区间所有点的$LCA$. 我们把$1$到$n$的$DFS$序全部求出来……然后设$i$的$DFS$序为$c[i]$,$pc[i]$为$c ...

  3. HDU 5266 pog loves szh III ( LCA + SegTree||RMQ )

    pog loves szh III Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Oth ...

  4. HDU 5266 pog loves szh III (线段树+在线LCA转RMQ)

    题目地址:HDU 5266 这题用转RMQ求LCA的方法来做的很easy,仅仅须要找到l-r区间内的dfs序最大的和最小的就能够.那么用线段树或者RMQ维护一下区间最值就能够了.然后就是找dfs序最大 ...

  5. HDU 5266 pog loves szh III 线段树,lca

    Pog and Szh are playing games. Firstly Pog draw a tree on the paper. Here we define 1 as the root of ...

  6. HDU 5266 pog loves szh III (LCA)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5266 题目就是让你求LCA,模版题.注意dfs会栈溢出,所以要扩栈,或者用bfs写. #pragma ...

  7. hdu 5265 pog loves szh II

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5265 pog loves szh II Description Pog and Szh are pla ...

  8. hdu 5264 pog loves szh I

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5264 pog loves szh I Description Pog has lots of stri ...

  9. hdu 5264 pog loves szh I 水题

    pog loves szh I Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?p ...

随机推荐

  1. PHP视频教程 > PHP面向对象编程视频教程

    当前位置: 主页 > 编程开发 > PHP视频教程 > PHP面向对象编程视频教程 > kingstone金士顿手机内存卡16G仅65元 1.1.什么是面向对象和类 上传日期: ...

  2. Cocos2dx隐藏iOS7状态栏】通过添加Plist Key隐藏iOS7状态栏

    本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi)  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/%e9%9a% ...

  3. 微软职位内部推荐-Senior Engineering Lead

    微软近期Open的职位: Job Title: Senior Engineering LeadDivision: Microsoft Business SolutionWork Location: S ...

  4. hdu 3714 Error Curves(三分)

    http://acm.hdu.edu.cn/showproblem.php?pid=3714 [题意]: 题目意思看了很久很久,简单地说就是给你n个二次函数,定义域为[0,1000], 求x在定义域中 ...

  5. 使用Yeoman搭建 AngularJS 应用 (4) —— 让我们搭建一个网页应用

    在开发一个的网页传统工作流程中,你需要大量的时间去设置引用文件,下载依赖文件,并且手动的创建网页文件结构.Yeoman生成器将会帮助你完成这些.让我们安装一个AngularJS项目的生成器. 安装An ...

  6. 360随身wifi怎样购买?360随身wifi怎样预约?

    ---恢复内容开始--- 360随身wifi怎样购买 想要购买360随身Wifi,可以登录360随身Wifi的官网wifi.360.cn,或者直接登陆京东商城进行购买,售价为19.9元,分黑.白两色. ...

  7. C#跳出循环的几种方法的区别

    break是循环结束执行,执行循环体后面的代码. continue是跳过本次循环未执行的代码,继续执行下一次循环. goto是跳到指定的指令去,你指哪,他跳到哪. return是函数返回,如果循环在M ...

  8. linux下c/c++ IDE开发工具介绍

    为避免以下某个软件安装时不自动安装 build-essential 不妨先执行: sudo apt-get install build-essential [编辑 ]anjuta Anjuta Dev ...

  9. 接口和JAVA设计模式

  10. ue标签不见了,如何解决?

    小问题,但是很恶心...如下图: 解决方法: 右键点击[菜单栏]右边的空白处,选择advanced,默认是basic,这时菜单栏中的菜单条目会变多,然后选择[视图]---[视图/列表]---[打开文件 ...