HdU5266(LCA + 线段树)

pog loves szh III

Accepts: 63

Submissions: 483

Time Limit: 12000/6000 MS (Java/Others)

Memory Limit: 131072/131072 K (Java/Others)

问题描述

pog在与szh玩游戏,首先pog在纸上画了一棵有根树,这里我们定义1为这棵树的根,然后szh在这棵树中选了若干个点,想让pog帮忙找找这些点的最近公共祖先在哪里,一个点为S的最近公共祖先当且仅当以该点为根的子树包含S中的所有点,且该点深度最大。然而,这个问题是十分困难的,出于szh对pog的爱,他决定只找编号连续的点,即li~ri。

输入描述

若干组数据(不超过3组n≥10000或Q≥10000)。
每组数据第一行一个整数n(1≤n≤300000),表示树的节点个数。
接下来n?1行,每行两个数Ai,Bi,表示存在一条边连接这两个节点。
接下来一行一个数Q(1≤Q≤300000),表示有Q组询问。
接下来Q行每行两个数li,ri(1≤li≤ri≤n),表示询问编号为li~ri的点的最近公共祖先。

输出描述

对于每组的每个询问,输出一行,表示编号为li~ri的点的最近公共祖先的编号。

输入样例

5
1 2
1 3
3 4
4 5
5
1 2
2 3
3 4
3 5
1 5

输出样例

1
1
3
3
1

Hint

珍爱生命,远离爆栈。

Statistic | Submit | Clarifications | Back

预处理之后LCA是O(1)的,然后用线段树就能在logn的时间里得出询问结果啦!

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 3e5 + 10;
const int inf = 1e8;
int pos[maxn],depth[maxn],head[maxn];
int d[maxn<<1][20],width[maxn<<1],tot,e;
typedef pair<int,int> Edge;
Edge edges[maxn<<1];
void AddEdge(int u,int v)
{
    edges[++e] = make_pair(v,head[u]);head[u] = e;
    edges[++e] = make_pair(u,head[v]);head[v] = e;
}
void pre(int u,int fa,int dep = 0)
{
    d[++tot][0] = u;
    if(!pos[u]) {
        pos[u] = tot;
        depth[u] = dep;
    }
    for(int eid = head[u]; eid ; eid = edges[eid].second) {
        int &v = edges[eid].first;
        if(v==fa)continue;
        pre(v,u,dep+1);
        d[++tot][0] = u;
    }
}
void RMQ_init(int n)
{
    for(int j = 1; (1<<j) <= n; j++) {
        for(int i = 1; i + (1<<j) - 1 <= n; i++) {
            d[i][j] = depth[d[i][j-1]] < depth[d[i+(1<<(j-1))][j-1]] ? d[i][j-1] : d[i+(1<<(j-1))][j-1];
        }
    }
    for(int i = 1,w = 1; i <= n; i++) {
        if((1<<w) <= i) w++;
        width[i] = w;
    }
}
int LCA(int u,int v)
{
    int L = pos[u],R = pos[v];
    if(L > R) swap(L,R);
    int k = width[R-L+1] - 1;
    return depth[d[L][k]] < depth[d[R-(1<<k)+1][k]] ? d[L][k] : d[R-(1<<k)+1][k];
}
int seg[maxn<<1];
void built(int o,int L,int R)
{
    if(L==R) {
        seg[o] = L;
        return;
    }
    int mid = (L + R) >> 1;
    built(o<<1,L,mid);
    built(o<<1|1,mid+1,R);
    seg[o] = LCA(seg[o<<1],seg[o<<1|1]);
}
int ql,qr;
int Query(int o,int L,int R)
{
    if(ql<=L&&qr>=R) {
        return seg[o];
    }
    int mid = (L + R) >> 1;
    int ans = -1;
    if(ql <= mid) ans = Query(o<<1,L,mid);
    if(qr > mid) {
        int t = Query(o<<1|1,mid+1,R);
        if(ans==-1) ans = t;
        else ans = LCA(ans,t);
    }
    return ans;
}
int main(int argc, char const *argv[])
{
    int n;
    while(scanf("%d",&n)==1) {

        memset(head,0,sizeof(head[0])*(n+1));
        for(int i = 1; i < n; i++) {
            int u, v;scanf("%d%d",&u,&v);
            AddEdge(u,v);
        }
        e = tot = 0;
        memset(pos,0,sizeof(pos[0])*(n+1));
        pre(1,-1);
        RMQ_init(tot);
        built(1,1,n);
        int Q;scanf("%d",&Q);
        while(Q--) {
            scanf("%d%d",&ql,&qr);
            if(ql > qr) swap(ql,qr);
            printf("%d\n", Query(1,1,n));
        }
    }
    return 0;
}
时间: 2024-07-28 22:00:18

HdU5266(LCA + 线段树)的相关文章

BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2243 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写

LCA+线段树/树状数组 POJ2763 Housewife Wind

Housewife Wind Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 11250   Accepted: 3111 Description After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beauti

HDU 5274(LCA + 线段树)

Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 747    Accepted Submission(s): 144 Problem Description Dylans is given a tree with  nodes. All nodes have a value .Nodes on t

hdu5274 Dylans loves tree LCA+线段树

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5274 在树上的询问和操作,每次修改单点值,询问两点之间出现次数为奇数的点权是什么,若没有输出-1.询问保证两点间至多只有一个数出现奇数次. 有一种经典的将树上的点转化成序列的方法,我们用dfs遍历这棵树,那么对于一个节点,他一点比他的子树即子节点先访问到,且当他的最后一个子节点的所有子树也都访问完时,这中间访问的节点一定都是他的子树.那么我们可以在访问时做一下记录,每个点首先被访问的clock,和结束时

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") /*****************************************

LCA+线段树 NOIP2016 天天爱跑步

天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nnn个结点和 n?1n-1n?1条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从111到nnn的连续正整数. 现在有mmm个玩家,第iii个玩家的起点为 SiS_iS?i??,终点为 TiT_iT?i?? .每天打卡任务开始时,所有玩家在第000秒同时从自己的起点出

【BZOJ2588】【Spoj 10628.】 Count on a tree 可持久化线段树+lca

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45048639"); } 题解: 对于每个树上节点存一个版本的可持久化线段树,为它到根节点上所有权值的权值线段树(需要离散化). 然后对于每次询问,这条链(a,b)的线段树就是:线段树a+线段树b?线段树lca?线段树falca 然后

HDU5266[XSYOJ2315]LCA_LCA_线段树

HDU5266 LCA Description 给一棵 n 个点的树,Q 个询问 [L,R] : 求点 L , 点 L+1 , 点 L+2 -- 点 R 的 LCA. Input 多组数据. The following line contains an integers,n(2≤n≤300000). AT The following n?1 line, two integers are bi and ci at every line, it shows an edge connecting bi

51 nod 1766 树上的最远点对(线段树+lca)

1766 树上的最远点对 基准时间限制:3 秒 空间限制:524288 KB 分值: 80 难度:5级算法题 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d} (PS 建议使用读入优化) Input 第一行一个数字 n n<=100000. 第二行到第n行每行三个数字描述路的情况, x,y,z (1<=x,y<=n,1<