Tunnel Warfare HDU - 1540 (线段树不同子树的合并)

在抗日战争期间,华北平原广大地区进行了大规模的隧道战。 一般来说,通过隧道连接的村庄排成一列。 除了两端,每个村庄都与两个相邻的村庄直接相连。
入侵者经常对一些村庄发动袭击并摧毁其中的部分隧道。 八路军指挥官要求最新的隧道和村庄连接状态。 如果某些村庄严重隔离,必须立即恢复连接!
Input
输入的第一行包含两个正整数n和m(n,m≤50,000),表示村庄和事件的数量。 接下来的m行中的每一行描述一个事件。
以下所示的不同格式描述了三种不同的事件:
D x:第x个村庄被毁。
Q x:指挥官询问第x个村庄与其直接或间接相关的村庄数量。
R:最后毁坏的村庄被重建了。
Output
按顺序输出每个指挥官询问的答案。
Sample Input
7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4
Sample Output
1
0
2
4
分析:
维护每个节点所对应区间的左最长1串,右最长一串和区间最长1串。查询的时候如果当前区间最长1串长度为0或者满,直接返回0\满;如果x位于当前区间的“中部”(左孩子的右和右孩子的左连接而成),直接返回中部长度;除此以外就继续查找。
代码:
1 #include <bits/stdc++.h>//题目也没说多组输入啊,WA了好多次,想哭 2 using namespace std; 3 const int maxn = 5 * 1e4 + 10; 4 struct node 5 { 6 int l, r; 7 int ln, rn, mn; 8 }t[maxn << 2]; 9 10 int n, m; 11 12 void pushup(int tar) 13 { 14 t[tar].ln = t[tar << 1].ln, t[tar].rn = t[tar << 1 | 1].rn; 15 t[tar].mn = max(t[tar << 1].mn, t[tar << 1 | 1].mn); 16 t[tar].mn = max(t[tar].mn, t[tar << 1].rn + t[tar << 1 | 1].ln); 17 if (t[tar << 1].ln == t[tar << 1].r - t[tar << 1].l + 1) t[tar].ln = t[tar << 1].ln + t[tar << 1 | 1].ln; 18 if (t[tar << 1 | 1].rn == t[tar << 1 | 1].r - t[tar << 1 | 1].l + 1) t[tar].rn = t[tar << 1 | 1].rn + t[tar << 1].rn; 19 } 20 21 void build(int l, int r, int tar) 22 { 23 t[tar].l = l, t[tar].r = r; 24 t[tar].ln = t[tar].rn = t[tar].mn = r - l + 1; 25 if (l == r) return; 26 int mid = (l + r) >> 1; 27 build(l, mid, tar << 1); 28 build(mid + 1, r, tar << 1 | 1); 29 } 30 31 void update(int x, int state, int tar) 32 { 33 if (t[tar].l == t[tar].r) 34 { 35 t[tar].ln = t[tar].rn = t[tar].mn = state; 36 return; 37 } 38 int mid = (t[tar].l + t[tar].r) >> 1; 39 if (x <= mid) update(x, state, tar << 1); 40 else if (x > mid) update(x, state, tar << 1 | 1); 41 pushup(tar); 42 } 43 44 int query(int x, int tar)//查询依据为,x必然存在于某个区间的中心部分,叶子节点除外,所以对叶子节点特判。 45 { 46 47 if (t[tar].l == t[tar].r) return 0;//如果是叶子节点直接输出0,说明48 int mid = (t[tar].l + t[tar].r) >> 1; 49 if (x >= t[tar << 1].r - t[tar << 1].rn + 1 && x <= t[tar << 1 | 1].l + t[tar << 1 | 1].ln - 1) return t[tar << 1].rn + t[tar << 1 | 1].ln; 50 else if (x <= mid) return query(x, tar << 1); 51 else return query(x, tar << 1 | 1); 52 } 53 54 int main() 55 { 56 int n, m; 57 58 while (cin >> n >> m) 59 { 60 stack<int> s; 61 char ope[2]; 62 int x; 63 64 build(1, n, 1); 65 while (m--) 66 { 67 cin >> ope; 68 if (ope[0] == 'D') 69 { 70 cin >> x; 71 s.push(x); 72 update(x, 0, 1); 73 } 74 else if (ope[0] == 'R') 75 { 76 x = s.top(); 77 s.pop(); 78 update(x, 1, 1); 79 } 80 else 81 { 82 cin >> x; 83 cout << query(x, 1) << endl; 84 } 85 } 86 } 87 }
分类:
线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如果单表数据量大,只能考虑分库分表吗?
· 一文彻底搞懂 MCP:AI 大模型的标准化工具箱
· 电商平台中订单未支付过期如何实现自动关单?
· 用 .NET NativeAOT 构建完全 distroless 的静态链接应用
· 为什么构造函数需要尽可能的简单
· Google发布A2A开源协议:“MCP+A2A”成未来标配?
· C# 多项目打包时如何将项目引用转为包依赖
· 一款让 Everything 更加如虎添翼的 .NET 开源辅助工具!
· 如果单表数据量大,只能考虑分库分表吗?
· 在Winform开发框架支持多种数据库基础上,增加对国产数据库人大金仓的支持