题意:给出一棵树,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. EXTJS4.2 chart 柱状图

    chart 柱状图 Ext.require('Ext.chart.*'); Ext.require(['Ext.Window', 'Ext.fx.target.Sprite', 'Ext.layout ...

  2. Lua基础之coroutine(协程)

    概括:1.创建协程2.coroutine的函数3.coroutine的基本流程4.yield对coroutine流程的干预5.resume, function()以及yield之间的参数传递和返回值传 ...

  3. UITextField监听文字输入事件

    [textField addTarget:self action:@selector(textFieldDidChange:)forControlEvents:UIControlEventEditin ...

  4. c++ 16 this 和 继承 及继承机制中的构造函数 与 析构函数

    #include <iostream> #include <string> using namespace std; class Animal { public: Animal ...

  5. 学习javascript总结下来的性能优化的小知识(一)

    http://www.cnblogs.com/ctriphire/p/4115525.html http://www.cnblogs.com/xjchenhao/archive/2012/10/22/ ...

  6. 线程以及数据对象的wait()和notifyAll()方法

    正在运行的程序称作一个进程,一个进程可以包含多个线程,这些线程可以共享进程的资源,它们共用一块存储空间.那么,各个线程在访问同一个数据对象的同时,可能引起冲突,以生产者.消费者为例,就会出现队列中没有 ...

  7. Nagios+msn+fetion自定义时间发送报警消息

    转自http://blog.csdn.net/deccmtd/article/details/6063467 Nagios+fetion发送手机报警使用了几个月.每次报警短信来都要看下手机.感觉麻烦. ...

  8. POJ2739Sum of Consecutive Prime Numbers

    http://poj.org/problem?id=2739 题意 :一个正整数能够表示为一个或多个连续素数和,给你一个正整数,让你求,有多少个这样的表示.例如:整数53有两种表示方法,5+7+11+ ...

  9. MetadataType的使用

    MetadataType的使用,MVC的Model层数据验证指定要与数据模型类关联的元数据类 using System.ComponentModel.DataAnnotations; //指定要与数据 ...

  10. 使用JS动态创建含有1000行的表格

    function addTable(){ createTable1(1000); //createTable2(1000); //createTable3(1000); //createTable4( ...