HDU5266---pog loves szh III (线段树+LCA)

题意:N个点的有向树, Q次询问, 每次询问区间[L, R]内所有点的LCA。

大致做法:线段树每个点保存它的孩子的LCA值, 对于每一次询问只需要 在线段树查询即可。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int MAXN = 3e5+10;
  4 struct Edge{
  5     int to, next;
  6 }e[MAXN << 1];
  7 int head[MAXN], tot_edge;
  8 void Add_Edge (int x, int y){
  9     e[tot_edge].to = y;
 10     e[tot_edge].next = head[x];
 11     head[x] = tot_edge++;
 12 }
 13 int n, q, MAX_LOG_V;
 14 bool vis[MAXN];
 15 void init (){
 16     MAX_LOG_V = 20;
 17     tot_edge = 0;
 18     memset(head, -1, sizeof (head));
 19     memset(vis, false, sizeof (vis));
 20 }
 21 int dep[MAXN], pa[25][MAXN];
 22 void DFS (int r, int pre, int d){                    // DFS 或 BFS都可以, G++下BFS
 23     dep[r] = d;
 24     pa[0][r] = pre;
 25     for (int i = head[r]; ~i; i = e[i].next){
 26         int u = e[i].to;
 27         if (pre != u){
 28             DFS(u, r, d+1);
 29         }
 30     }
 31 }
 32 void BFS (int r, int pre, int d){
 33     dep[r] = d;
 34     pa[0][r] = pre;
 35     queue <int>Q;
 36     Q.push(r);
 37     vis[r] = true;
 38     while (!Q.empty()){
 39         int u = Q.front();
 40         Q.pop();
 41         for (int i = head[u]; ~i; i = e[i].next){
 42             int v = e[i].to;
 43             if (!vis[v]){
 44                 dep[v] = dep[u] + 1;
 45                 pa[0][v] = u;
 46                 Q.push(v);
 47                 vis[v] = true;
 48             }
 49         }
 50     }
 51 }
 52 void pre_solve (){
 53     BFS(1, -1, 0);
 54     for (int k = 0; k + 1 < MAX_LOG_V; k++){
 55         for (int v = 1; v <= n; v++){
 56             if (pa[k][v] < 0){
 57                 pa[k+1][v] = -1;
 58             }else{
 59                 pa[k+1][v] = pa[k][pa[k][v]];
 60             }
 61         }
 62     }
 63 }
 64 int LCA (int u, int v){
 65     if (dep[u] > dep[v]){
 66         swap(u, v);
 67     }
 68     for (int k = 0; k < MAX_LOG_V; k++){
 69         if ((dep[v] - dep[u]) >> k & 1){
 70             v = pa[k][v];
 71         }
 72     }
 73     if (u == v){
 74         return u;
 75     }
 76     for (int k = MAX_LOG_V-1; k >= 0; k--){
 77         if (pa[k][u] != pa[k][v]){
 78             u = pa[k][u];
 79             v = pa[k][v];
 80         }
 81     }
 82     return pa[0][u];
 83 }
 84 int seg[MAXN << 2];
 85 void push_up(int pos){
 86     seg[pos] = LCA(seg[pos<<1], seg[pos<<1|1]);
 87 }
 88 void build (int l, int r, int pos){
 89     if (l == r){
 90         seg[pos] = l;
 91         return ;
 92     }
 93     int mid = (l + r) >> 1;
 94     build(l, mid, pos<<1);
 95     build(mid+1, r, pos<<1|1);
 96     push_up(pos);
 97 }
 98 int query (int l, int r, int pos, int ua, int ub){
 99     if (ua <= l && ub >= r){
100         return seg[pos];
101     }
102     int mid = (l + r) >> 1;
103     int t1 = -1, t2 = -1;
104     if (ua <= mid){
105         t1 = query(l, mid, pos<<1, ua, ub);
106     }
107     if (ub > mid){
108         t2 = query(mid+1, r, pos<<1|1, ua, ub);
109     }
110     if (t1 == -1 || t2 == -1){
111         return max(t1, t2);
112     }else{
113         return LCA(t1, t2);
114     }
115 }
116 int main()
117 {
118     #ifndef ONLINE_JUDGE
119         freopen("in.txt","r",stdin);
120     #endif
121     while (~ scanf ("%d", &n)){
122         init();
123         for (int i = 0; i < n-1; i++){
124             int u, v;
125             scanf ("%d%d", &u, &v);
126             Add_Edge(u, v);
127             Add_Edge(v, u);
128         }
129         pre_solve();
130         build(1, n, 1);
131         scanf ("%d", &q);
132         for (int i = 0; i < q; i++){
133             int ua, ub;
134             scanf ("%d%d", &ua, &ub);
135             printf("%d\n", query(1, n, 1, ua, ub));
136         }
137     }
138     return 0;
139 }
时间: 2024-10-12 05:14:22

HDU5266---pog loves szh III (线段树+LCA)的相关文章

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> #inc

[HDU5266]pog loves szh III

首先dfs,记录每个点第一次被访问到的时间 那么区间LCA其实就是访问最早和访问最晚的点的LCA 找时间最早和最晚用ST表,找LCA用倍增 1 #include<stdio.h> 2 #include<string.h> 3 int n,tot,dfsclk,h[300010],nex[600010],to[600010],dfsnum[300010],dfsid[300010],dep[300010],fa[300010][20],stmin[300010][20],stmax[

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 (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 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)  ,表

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<

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当然想让恩爱值越高越好,并且他们

【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 然后