HDU-1540 Tunnel Warfare 线段树
http://acm.hdu.edu.cn/showproblem.php?pid=1540
题义是对于一段线段,D x 表示破坏x点,R 表示回复最近一次被破坏的点,Q x表示询问以x点为中心的两头的最长的连续区间。改了2个小时,终于A掉了,吐血啊,尤其是杭电的测试数据,一个点可以破坏多次,这小日本鬼子也忒坏吧,再说了如果一个点破坏多次,八路军叔叔也要修理多次吗,题义与实际既不符合,还是POJ厚道。
该题分两部来做,首先是建立一棵线段树,这颗线段树应该保留有一下信息:
1. 该区间的左连续长度,右连续长度
2. 该区间的覆盖情况(即是否没有发生任何破坏)这是线段树以空间换时间的地方
然后就是求连续的区间长度了,我得出结果的步骤是这样的:
A. 首先判定这个节点(x)是否已经被摧毁,如果摧毁直接返回0
B. 如果没有被摧毁的话,就求1 ~ x-1 的右连续段以及 x+1 ~ N 的左连续段再加上自己本身的1
对于R操作的话,用意个stack就行了,注意杭电的一个点可以被多次破坏。
代码如下:
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <stack>
#define MAXN 50005
using namespace std;
struct Node
{
int l, r;
int lenl, lenr, cover;
}seg[MAXN*3];
char rec[MAXN];
void creat(int f, int l, int r)
{
int mid = (l+r)>>1;
seg[f].l = l, seg[f].r = r;
seg[f].lenl = r-l;
seg[f].lenr = r-l;
seg[f].cover = 1;
if (r - l > 1)
{
creat(f<<1, l, mid);
creat(f<<1|1, mid, r);
}
}
void modify(int f, int l, int r, int val)
{
int mid = (seg[f].l + seg[f].r)>>1;
if (seg[f].l == l && r == seg[f].r)
{
seg[f].lenl = seg[f].lenr = val;
seg[f].cover = val;
}
else if (seg[f].r - seg[f].l > 1)
{
if (seg[f].cover == 1)
{ // lazy 操作
seg[f<<1].cover = seg[f].cover;
seg[f<<1|1].cover = seg[f].cover;
seg[f].cover = 0;
}
if (r <= mid)
modify(f<<1, l, r, val);
else if (l >= mid)
modify(f<<1|1, l, r, val);
else
{
modify(f<<1, l, mid, val);
modify(f<<1|1, mid, r, val);
}
seg[f].lenl = seg[f<<1].lenl;
seg[f].lenr = seg[f<<1|1].lenr;
if (seg[f<<1].cover == 1)
seg[f].lenl += seg[f<<1|1].lenl;
if (seg[f<<1|1].cover == 1)
seg[f].lenr += seg[f<<1].lenr;
// 更新左右区间的连续长度
seg[f].cover = seg[f<<1].cover && seg[f<<1|1].cover;
// 回溯cover的值
}
}
int lquery(int f, int l, int r)
{
int mid = (seg[f].l+seg[f].r)>>1;
if (seg[f].l == l && r == seg[f].r)
{
return seg[f].lenl;
}
else if (seg[f].r - seg[f].l > 1)
{
if (r <= mid)
return lquery(f<<1, l, r);
else if (l >= mid)
return lquery(f<<1|1, l, r);
else
{
int c = lquery(f<<1, l, mid);
if (c == mid-l)
{
c += lquery(f<<1|1, mid, r);
}
return c;
}
}
else return 0;
}
int rquery(int f, int l, int r)
{
int mid = (seg[f].l+seg[f].r)>>1;
if (seg[f].l == l && r == seg[f].r)
{
return seg[f].lenr;
}
else if (seg[f].r - seg[f].l > 1)
{
if (r <= mid)
return rquery(f<<1, l, r);
else if (l >= mid)
return rquery(f<<1|1, l, r);
else
{
int c = rquery(f<<1|1, mid, r);
if (c == r-mid)
{
c += rquery(f<<1, l, mid);
}
return c;
}
}
else
return 0;
}
int main()
{
int N, M, x;
char op[10];
while (scanf("%d %d", &N, &M) == 2)
{
stack<int>stk;
memset(rec, 1, sizeof (rec));
creat(1, 1, N+1);
for (int i = 0; i < M; ++i)
{
scanf("%s", op);
if (op[0] == 'R')
{
if (!stk.empty())
{
int c = stk.top();
rec[c] = 1;
stk.pop();
modify(1, c, c+1, 1);
}
}
else if (op[0] == 'D')
{
scanf("%d", &x);
rec[x] = 0;
stk.push(x);
modify(1, x, x+1, 0);
}
else
{
scanf("%d", &x);
if (rec[x] == 0)
printf("0\n");
else
printf("%d\n", lquery(1, x+1, N+1)+rquery(1, 1, x)+1);
}
}
}
return 0;
}