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 }

 

转载于:https://www.cnblogs.com/oneshot/p/4561916.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值