HDU - 1540 Tunnel Warfare(线段树 区间合并)
2015-10-21 10:17
453 查看
题目大意:给你N个点,相邻的点连线。现在有3种操作
D x:破坏和x相连的线
Q x:x和几个点相连
R:修复刚被破坏的点的连接
解题思路:刚破坏的点可以用一个栈来存储。现在的问题是,怎么求一个点和几个点相连
我们维护区间的三个值,从最左端往右的连续没有被破坏的点数量lsum,从最右端开始往左的连续的没有被破坏的点的数量rsum,区间内最长的连续的没有被破坏的点的数量tsum
询问的时候可以这样做,首先先判断一下该点所属的区间的tsum,如果tsum为0,表示这个区间内没有点连通,那么返回的就是0了,如果tsum == (r - l + 1)表示所有的点都被连接起来了,那么返回(r - l + 1)
如果都不是的话,判断一下该点属于左区间还是右区间
假设属于左区间,那就要判断一下,该点是否在左区间的rsum范围内,如果在该范围内,表示该点和mid相连,所以还得查询一下右区间,找寻和mid + 1相连的点的数量。如果不在rsum的范围内,直接递归查找下去
右区间的情况和左区间的情况类似
D x:破坏和x相连的线
Q x:x和几个点相连
R:修复刚被破坏的点的连接
解题思路:刚破坏的点可以用一个栈来存储。现在的问题是,怎么求一个点和几个点相连
我们维护区间的三个值,从最左端往右的连续没有被破坏的点数量lsum,从最右端开始往左的连续的没有被破坏的点的数量rsum,区间内最长的连续的没有被破坏的点的数量tsum
询问的时候可以这样做,首先先判断一下该点所属的区间的tsum,如果tsum为0,表示这个区间内没有点连通,那么返回的就是0了,如果tsum == (r - l + 1)表示所有的点都被连接起来了,那么返回(r - l + 1)
如果都不是的话,判断一下该点属于左区间还是右区间
假设属于左区间,那就要判断一下,该点是否在左区间的rsum范围内,如果在该范围内,表示该点和mid相连,所以还得查询一下右区间,找寻和mid + 1相连的点的数量。如果不在rsum的范围内,直接递归查找下去
右区间的情况和左区间的情况类似
#include <cstdio> #include <cstring> #include <algorithm> #include <stack> using namespace std; const int N = 50010 << 2; int lsum , rsum , tsum , mark ; int n, m; void build(int u, int l, int r) { lsum[u] = rsum[u] = tsum[u] = r - l + 1; mark[u] = -1; if (l == r) return ; int mid = (l + r) >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r); } void Update(int u, int l, int r) { lsum[u] = rsum[u] = tsum[u] = mark[u] ? 0 : r - l + 1; } void PushDown(int u, int l, int r) { if (mark[u] == -1) return ; mark[u << 1] = mark[u << 1 | 1] = mark[u]; mark[u] = -1; int mid = (l + r) >> 1; Update(u << 1, l, mid); Update(u << 1 | 1, mid + 1, r); } void PushUp(int u, int l, int r) { tsum[u] = max(max(tsum[u << 1], tsum[u << 1 | 1]), rsum[u << 1] + lsum[u << 1 | 1]); lsum[u] = lsum[u << 1]; rsum[u] = rsum[u << 1 | 1]; int mid = (l + r) >> 1; if (lsum[u] == mid - l + 1) lsum[u] += lsum[u << 1 | 1]; if (rsum[u] == r - mid) rsum[u] += rsum[u << 1]; } void Modify(int u, int l, int r, int pos, int c) { if (l == r) { mark[u] = c; Update(u, l, r); return ; } PushDown(u, l, r); int mid = (l + r) >> 1; if (pos <= mid) Modify(u << 1, l, mid, pos, c); else Modify(u << 1 | 1, mid + 1, r, pos, c); PushUp(u, l, r); } int Query(int u, int l, int r, int pos) { if (l == r || tsum[u] == 0 || tsum[u] == r - l + 1) return tsum[u]; PushDown(u, l, r); int mid = (l + r) >> 1; if (pos <= mid) { int tmp = mid - rsum[u << 1] + 1; if (pos >= tmp) return Query(u << 1, l, mid, pos) + Query(u << 1 | 1, mid + 1, r, mid + 1); else return Query(u << 1, l, mid, pos); } else { int tmp = mid + lsum[u << 1 | 1]; if (pos <= tmp) return Query(u << 1 | 1, mid + 1, r, pos) + Query(u << 1, l, mid, mid); else return Query(u << 1 | 1, mid + 1, r, pos); } } void solve() { stack<int> Stack; build(1, 1, n); char op[4]; int pos; while (m--) { scanf("%s", op); if (op[0] == 'R') { if (Stack.empty()) continue; pos = Stack.top(); Stack.pop(); Modify(1, 1, n, pos, 0); } else if (op[0] == 'D') { scanf("%d", &pos); Stack.push(pos); Modify(1, 1, n, pos, 1); } else { scanf("%d", &pos); printf("%d\n", Query(1, 1, n, pos)); } } } int main() { while (scanf("%d%d", &n, &m) != EOF) solve(); return 0; }
相关文章推荐
- 线性方程组(A是上三角矩阵时)的C++求解
- 重新理解Java的抽象类和接口
- java静态代码调用顺序
- QT事件--阐述的比较系统
- Ubuntu 上文件共享
- js-预编译就是那个鬼
- Chrome浏览器扩展开发系列之十九:扩展开发示例
- 解决SVN CONNOT VERIFY LOCK ON PATH NO MATCHING LOCK-TOKEN AVAILABLE
- Linux Shell之sort命令
- Linux Shell之sort命令
- 分布式事务讲解
- 上亿邮箱数据库被曝泄露,密码还值得你相信?
- 关于STL中map的erase迭代器是否失效的讨论
- Python学习之安装WingIDE并破解
- 提升网站性能开发的10个技巧
- ZooKeeper系列之八:ZooKeeper的简单操作
- jQuery :eq() 选择器
- [架构师]怎么成为一个软件架构师
- svn : Can not Parse lock / entries hashfile错误解决办法
- git branch -D 大写的D 删除分支