Tunnel Warfare

                                                            Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768
K (Java/Others)

                                                                                                                       链接:hdu 1540        POJ
2892

 Problem Description 
During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly connected
with two neighboring ones.

Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration
of connection must be done immediately!
Input
The first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event.



There are three different events described in different format shown below:



D x: The x-th village was destroyed.



Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.



R: The village destroyed last was rebuilt.
Output
Output the answer to each of the Army commanders’ request in order on a separate line.
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

题意:

给定N个点。点的编号是从1 ~ N,M次‘Q’或‘D或‘R’的操作,“D  x”表示的是破坏这个点x,“R”是修复之前破坏的点,“Q x”表示询问点x所在连续区间的长度。假定最初每一个点都是好的。

分析:

首先对操作进行分析:能够把D操作看成把区间在点x出截断,R操作是把x左右【包含点x】进行合并。

每次合并两个区间 [a,b] , [c,d] 的时候,得到的新的区间[a,d] 的最大连续区间长度为:

Len(a,d)  =  max{ Len(a,b),Len(c,d) ,End(b) + Begin(c) };  <==有一点分治的思想

End(b)表示以b结尾的最大连续区间长度。Begin(c)表示以c开头的最大连续区间长度,这里我们能够知道,合并两个区间,并非简单的区间加减。而是还要保持一个以区间第一个元素開始的最大连续区间长度以及 以区间最后一个元素结尾的最大连续区间长度。

那么。如今问题就比較好办了。线段树每一个节点包括三个信息。各自是以区间第一个元素開始的最大连续区间长度ln。以区间最后一个元素结尾的最大连续区间长度rn,以及区间最大连续长度mn。

接下来,便是Q操作了,询问点x 所在连续区间的长度。

在递归左儿子节点的时候,注意一下,x是否在以左儿子区间最后一个元素结尾长度为左儿子rn的范围里面,假设在,那么x所在的连续区间便有可能包括右儿子的一部分,递归右儿子的时候,同理!

/****************************>>>>HEADFILES<<<<****************************/
#include <set>
#include <map>
#include <list>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;
/****************************>>>>>DEFINE<<<<<*****************************/
#define fst first
#define snd second
#define root 1,N,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PB(a) push_back(a)
#define MP(a,b) make_pair(a,b)
#define CASE(T) for(scanf("%d",&T);T--;)
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w",stdout)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef __int64 LL;
const int INF = 0x3f3f3f3f;
/****************************>>>>SEPARATOR<<<<****************************/
const int maxn = 50000 + 5;
int N, M;
struct Node
{
int ln, rn, mn;
} segtree[maxn << 4];
inline void PushUp(const int& rt, const int& l, const int& r)
{
segtree[rt].ln = segtree[rt << 1].ln;
segtree[rt].rn = segtree[rt << 1 | 1].rn;
segtree[rt].mn = max(segtree[rt << 1].rn + segtree[rt << 1 | 1].ln,
max(segtree[rt << 1].mn, segtree[rt << 1 | 1].mn));
int mid = (l + r) >> 1;
if(segtree[rt << 1].mn == mid - l + 1) segtree[rt].ln += segtree[rt << 1 | 1].ln;
if(segtree[rt << 1 | 1].mn == r - (mid + 1) + 1) segtree[rt].rn += segtree[rt << 1].rn;
}
void Build(int l, int r, int rt)
{
segtree[rt].ln = segtree[rt].rn = segtree[rt].mn = r - l + 1;
if(l == r)
{
return ;
}
int mid = (l + r) >> 1;
Build(lson);
Build(rson);
}
void Update(int pos, int val, int l, int r, int rt)
{
if(l == r)
{
segtree[rt].ln = segtree[rt].rn = segtree[rt].mn = val;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid)
Update(pos, val, lson);
else
Update(pos, val, rson);
PushUp(rt, l, r);
}
int Query(int pos, int l, int r, int rt)
{
if(r - l + 1 == segtree[rt].mn || r == l || segtree[rt].mn == 0)
{
return segtree[rt].mn;
}
int mid = (l + r) >> 1, ret = 0;
if(pos <= mid)
{
if(pos >= mid - segtree[rt << 1].rn + 1)
ret = Query(pos, lson) + Query(mid + 1, mid + 1, r, rt << 1 | 1);
else ret = Query(pos, lson);
}
else
{
if(pos <= (mid + 1) + segtree[rt << 1 | 1].ln - 1)
ret = Query(pos, rson) + Query(mid, l, mid, rt << 1);
else ret = Query(pos, rson);
}
return ret;
}
int destroy[maxn];
int main()
{
//FIN;
while(~scanf("%d %d", &N, &M))
{
Build(root);
char Op[5];
int x, cnt = 0;
for(int i = 0; i < M; i++)
{
scanf("%s", Op);
if(Op[0] == 'Q')
{
scanf("%d", &x);
printf("%d\n", Query(x, root));
}
else if(Op[0] == 'D')
{
scanf("%d", &x);
Update(x, 0, root);
destroy[cnt++] = x;
}
else
{
x = destroy[--cnt];
Update(x, 1, root);
}
}
}
}

一年之后,再写了一遍这个题目。感觉代码风格还是变化了一点。再贴个代码~

#include <bits/stdc++.h>

using namespace std;

const int MX = 5e4 + 5;

#define lch     (rt << 1)
#define rch (rt << 1 | 1) typedef pair<int, int> PII; struct Seg {
/**
* status:
* 0 -- Bad
* 1 -- Good
* -1 -- not cover
* I: 节点相应区间两端点以及两短点的标号
*/
int sum, status;
PII I[2];
} seg[MX * 3]; int N, M, x;
char oper[5]; inline void pushUp(int rt) {
if(seg[lch].status == seg[rch].status) seg[rt].status = seg[lch].status;
else seg[rt].status = -1; if(seg[lch].status == 1 && seg[rch].status == 1) seg[rt].sum = seg[lch].sum + seg[rch].sum;
else seg[rt].sum = 0;
} void build(int l, int r, int rt) {
int temp;
if(l == r) {
seg[rt].sum = seg[rt].status = 1;
seg[rt].I[0] = make_pair(l, rt);
seg[rt].I[1] = make_pair(r, rt);
return;
}
int mid = (l + r) >> 1;
build(l, mid, lch);
build(mid + 1, r, rch);
pushUp(rt);
seg[rt].I[0] = seg[lch].I[0];
seg[rt].I[1] = seg[rch].I[1];
} void update(int pos, int v, int l, int r, int rt) {
if(l == r) {
seg[rt].status = v;
seg[rt].sum = (v == 1) ? 1 : 0;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(pos, v, l, mid, lch);
else update(pos, v, mid + 1, r, rch);
pushUp(rt);
} int query_status(int pos, int l, int r, int rt) {
if(l == r) return seg[rt].status;
int mid = (l + r) >> 1;
if(pos <= mid) return query_status(pos, l, mid, lch);
else return query_status(pos, mid + 1, r, rch);
} int query(int pos, int l, int r, int rt, int d) {
if(seg[rt].status == 0) return 0;
int mid = (l + r) >> 1, ret = 0;
if(seg[rt].status == 1) {
ret += seg[rt].sum;
PII &lb = seg[rt].I[0], &ub = seg[rt].I[1];
if(lb.first != 1 && seg[lb.second].status == 1 && d != 1)
ret += query(lb.first - 1, 1, N, 1, -1);
if(ub.first != N && seg[ub.second].status == 1 && d != -1)
ret += query(ub.first + 1, 1, N, 1, 1);
return ret;
}
if(pos <= mid) {
ret += query(pos, l, mid, lch, d);
} else {
ret += query(pos, mid + 1, r, rch, d);
}
return ret;
} int main() {
// freopen("input.txt", "r", stdin);
while(~scanf("%d %d", &N, &M)) {
build(1, N, 1);
stack<int> buf;
while(M --) {
scanf("%s", oper);
if(oper[0] == 'D') {
scanf("%d", &x); buf.push(x);
update(x, 0, 1, N, 1);
} else if(oper[0] == 'Q') {
scanf("%d", &x);
int k = query_status(x, 1, N, 1), ans = 0;
if(k != 0) {
ans = query(x, 1, N, 1, 0);
}
printf("%d\n", ans);
} else {
if(buf.empty()) continue;
x = buf.top(); buf.pop();
update(x, 1, 1, N, 1);
}
}
}
return 0;
}

hdu 1540/POJ 2892 Tunnel Warfare 【线段树区间合并】的更多相关文章

  1. HDU 1540 POJ 2892 Tunnel Warfare

    线段树 区间合并 单点修改 区间查询.又是1秒钟构思,差错查了好久... ... 发现一个int型的定义成了char型,打脸. #include <stdio.h> #include &l ...

  2. HDU 1540 / POJ 2892 Tunnel Warfare (单点更新,区间合并,求包含某点的最大连续个数)

    题意:一条线上有n个点,D x是破坏这个点,Q x是表示查询x所在的最长的连续的点的个数,R是恢复上一次破坏的点. 思路:这题的关键是查询. 将被毁的村庄看成空位,当查询某个点的时候,如果我们知道它左 ...

  3. HDU 1540 Tunnel Warfare 线段树区间合并

    Tunnel Warfare 题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少 思路:一个节点的最大连续区间由(左儿子的最大的连续区间,右儿子的最大连续区 ...

  4. Tunnel Warfare 线段树 区间合并|最大最小值

    B - Tunnel WarfareHDU - 1540 这个有两种方法,一个是区间和并,这个我个人感觉异常恶心 第二种方法就是找最大最小值 kuangbin——线段树专题 H - Tunnel Wa ...

  5. HDU1540 Tunnel Warfare —— 线段树 区间合并

    题目链接:https://vjudge.net/problem/HDU-1540 uring the War of Resistance Against Japan, tunnel warfare w ...

  6. hdu 1540 Tunnel Warfare 线段树 区间合并

    题意: 三个操作符 D x:摧毁第x个隧道 R x:修复上一个被摧毁的隧道,将摧毁的隧道入栈,修复就出栈 Q x:查询x所在的最长未摧毁隧道的区间长度. 1.如果当前区间全是未摧毁隧道,返回长度 2. ...

  7. hdu 3911 Black And White (线段树 区间合并)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3911 题意: 给你一段01序列,有两个操作: 1.区间异或,2.询问区间最长的连续的1得长度 思路: ...

  8. HDU 3911 Black And White(线段树区间合并+lazy操作)

    开始以为是水题,结果...... 给你一些只有两种颜色的石头,0为白色,1为黑色. 然后两个操作: 1 l r 将[ l , r ]内的颜色取反 0 l r 计算[ l , r ]内最长连续黑色石头的 ...

  9. Poj 3667——hotel——————【线段树区间合并】

    Hotel Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 13124   Accepted: 5664 Descriptio ...

随机推荐

  1. VirtualBox虚拟机安装CentOS 7

    新建虚拟机 因为比较简单,所以对于VirtualBox就不做过多介绍了,直接下载安装即可,安装好之后打开Oracle VM VirtualBox管理器,点击新建,选择Red Hat(根据windows ...

  2. UVALive 3027 Corporative Network (带权并查集)

    题意: 有 n 个节点,初始时每个节点的父节点都不存在,你的任务是执行一次 I 操作 和 E 操作,含义如下: I  u  v   :  把节点 u  的父节点设为 v  ,距离为| u - v | ...

  3. [BZOJ 1567] Blue Mary的战役地图

    Link: BZOJ 1567 传送门 Solution: 矩阵Hash/二维$Hash$模板题 涉及到需要快速查询.匹配的题目,考虑直接上$Hash$ 矩阵$Hash$其实就是每行先各$Hash$一 ...

  4. 一些 iOS 常用的第三方库

    网络通信 AFNetworking 轻量级的通讯类库,使用非常简单.建议更新到最新版,前几天看新闻说之前有个逻辑性的 bug https://github.com/AFNetworking/AFNet ...

  5. Apache2 httpd.conf 配置详解

    Apache2 httpd.conf 配置详解 <第一部分> 常用配置指令说明 1. ServerRoot:服务器的基础目录,一般来说它将包含conf/和logs/子目录,其它配置文件的相 ...

  6. microsoft-sql-server release-notes

    https://docs.microsoft.com/en-us/sql/release-notes/microsoft-sql-server

  7. 彻底理解Javascript 中的 Promise(-------------------------------***---------------------------------)

    ES6原生提供了 Promise 对象. 到底是何方妖怪呢?打出来看看: 所谓 Promise,就是一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个 ...

  8. 基于CoreText的排版引擎

    前言 本人今年主要在负责猿题库iOS客户端的开发,本文旨在通过分享猿题库iOS客户端开发过程中的技术细节,达到总结和交流的目的. 这是本技术分享系列文章的第三篇.本文涉及的技术细节是:基于CoreTe ...

  9. Java程序猿修炼之道 之 Logging(3/3) - 怎么分析Log

    1. 说明 作为一个程序猿我们常常要做一件事情:获取某个Log文件,从当中找出自己想要的信息. 本文总结了我在工作中使用了哪些工具来分析Log文件获取我想要的信息,我近期几年的工作环境都是server ...

  10. IntelliJ IDEA和pycharm注册码

    BIG3CLIK6F-eyJsaWNlbnNlSWQiOiJCSUczQ0xJSzZGIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...