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

题目地址:HDU 5266

这题用转RMQ求LCA的方法来做的非常简单,只需要找到l-r区间内的dfs序最大的和最小的就可以,那么用线段树或者RMQ维护一下区间最值就可以了。然后就是找dfs序最大的点和dfs序最小的点的最近公共祖先了。

代码如下:

#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <set>
#include <stdio.h>
using namespace std;
#define LL __int64
#define pi acos(-1.0)
#define root 1, n, 1
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
#pragma comment(linker, "/STACK:1024000000")
const int mod=1e4+7;
const int INF=0x3f3f3f3f;
const double eqs=1e-9;
const int MAXN=300000+10;
int fir[MAXN], F[MAXN<<1], tot, deg[MAXN], rmq[MAXN<<1];
int head[MAXN], cnt, n;
int dp[MAXN<<1][30];
int Max[MAXN<<2], Min[MAXN<<2], q_max, q_min;
struct node
{
        int u, v, next;
}edge[MAXN<<1];
void add(int u, int v)
{
        edge[cnt].v=v;
        edge[cnt].next=head[u];
        head[u]=cnt++;
}
void init()
{
        memset(head,-1,sizeof(head));
        cnt=tot=0;
}
void dfs(int u, int dep, int fa)
{
        F[++tot]=u;
        rmq[tot]=dep;
        fir[u]=tot;
        for(int i=head[u];i!=-1;i=edge[i].next){
                int v=edge[i].v;
                if(v==fa) continue ;
                dfs(v,dep+1,u);
                F[++tot]=u;
                rmq[tot]=dep;
        }
}
struct ST
{
        int i, j;
        void init()
        {
                for(i=1;i<=tot;i++) dp[i][0]=i;
                for(j=1;(1<<j)<=tot;j++){
                        for(i=1;i<=tot-(1<<j)+1;i++){
                                dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<j-1)][j-1]]?dp[i][j-1]:dp[i+(1<<j-1)][j-1];
                        }
                }
        }
        int Query(int l, int r)
        {
                if(r<l) swap(l,r);
                int k=0;
                while((1<<k+1)<=r-l+1) k++;
                return rmq[dp[l][k]]<rmq[dp[r+1-(1<<k)][k]]?dp[l][k]:dp[r+1-(1<<k)][k];
        }
}st;
void PushUp(int rt)
{
        Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
        Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
}
void Build(int l, int r, int rt)
{
        if(l==r){
                Max[rt]=Min[rt]=fir[l];
                return ;
        }
        int mid=l+r>>1;
        Build(lson);
        Build(rson);
        PushUp(rt);
}
void Query(int ll, int rr, int l, int r, int rt)
{
        if(ll<=l&&rr>=r){
                q_max=max(q_max,Max[rt]);
                q_min=min(q_min,Min[rt]);
                return ;
        }
        int mid=l+r>>1;
        if(ll<=mid) Query(ll,rr,lson);
        if(rr>mid) Query(ll,rr,rson);
}
int main()
{
        int q, u, v, l, r, i;
        while(scanf("%d",&n)!=EOF){
                init();
                for(i=1;i<n;i++){
                        scanf("%d%d",&u,&v);
                        add(u,v);
                        add(v,u);
                }
                dfs(1,0,-1);
                st.init();
                Build(root);
                scanf("%d",&q);
                while(q--){
                        scanf("%d%d",&u,&v);
                        if(u>v) swap(u,v);
                        q_min=INF;
                        q_max=0;
                        Query(u,v,root);
                        //printf("%d %d\n",q_min,q_max);
                        printf("%d\n",F[st.Query(q_min,q_max)]);
                }
        }
        return 0;
}
时间: 2024-10-11 09:14:15

HDU 5266 pog loves szh III (线段树+在线LCA转RMQ)的相关文章

hdu 5266 pog loves szh III 在线lca+线段树区间优化

题目链接:hdu 5266 pog loves szh III 思路:因为它查询的是区间上的lca,所以我们需要用在线lca来处理,达到单点查询的复杂度为O(1),所以我们在建立线段树区间查询的时候可以达到O(1*nlgn)的时间复杂度 ps:因为栈很容易爆,所以.....你懂的 -->#pragma comment(linker, "/STACK:1024000000,1024000000") /*****************************************

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/Others)Total Submission(s): 470    Accepted Submission(s): 97 Problem Description Pog and Szh are playing games. Firstly Pog draw a tree on the paper. He

HDU 5266 pog loves szh III

题意:给出一棵树,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和

HDU 5266 pog loves szh III (LAC)

问题描述 pog在与szh玩游戏,首先pog在纸上画了一棵有根树,这里我们定义1为这棵树的根,然后szh在这棵树中选了若干个点,想让pog帮忙找找这些点的最近公共祖先在哪里,一个点为S的最近公共祖先当且仅当以该点为根的子树包含S中的所有点,且该点深度最大.然而,这个问题是十分困难的,出于szh对pog的爱,他决定只找编号连续的点,即l i   ~r i   . 输入描述 若干组数据(不超过3  组n≥10000  或Q≥10000  ). 每组数据第一行一个整数n(1≤n≤300000)  ,表

HDU 5266 pog loves szh III (LCA)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5266 题目就是让你求LCA,模版题.注意dfs会栈溢出,所以要扩栈,或者用bfs写. 1 #pragma comment(linker, "/STACK:102400000,102400000") //扩栈 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 using nam

hdu 5265 pog loves szh II STL

pog loves szh II Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5265 Description pog在与szh玩游戏,首先pog找到了一个包含n个数的序列,然后他在这n个数中挑出了一个数A,szh出于对pog的爱,在余下的n−1个数中也挑了一个数B,那么szh与pog的恩爱值为(A+B)对p取模后的余数,pog与szh当然想让恩爱值越高越好,并且他们

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?pid=5264 Description pog拥有很多字符串,它喜欢将两个长度相等字符串交错拼在一起,如abcd与efgh,那么交错拼在一起就成了aebfcgdh啦!szh觉得这并不好玩,因此它将第二个字符串翻转了一遍,如efgh变成了hgfe,然后再将这两个字符串交错拼在一起,因此abcd与efg

hdu 5264 pog loves szh I

题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5264 pog loves szh I Description Pog has lots of strings. And he always mixes two equal-length strings. For example, there are two strings: "abcd" and "efgh". After mixing, a new string &q

bc #43(hdu 5265) pog loves szh II

pog loves szh II Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2115    Accepted Submission(s): 609 Problem Description Pog and Szh are playing games.There is a sequence with n numbers, Pog wil