- 题目大意
D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少,然后根据命令来进行模拟操作。
- 解题思路
这个我是根据线段树的区间合并的模板来写的,用三个变量记录左边连续区间,右边连续区间和最大连续区间,用栈来存储点(修复的时候要用),其余的就是更新点,然后查询最大的连续区间。
- 代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
const int maxn = 50001;
struct node
{
int l, r;
int ls, rs, ms;
}t[4 * maxn];
void build(int l, int r, int k)
{
int mid;
t[k].l = l;
t[k].r = r;
t[k].ls = t[k].rs = t[k].ms = r - l + 1;
if (l == r)
return;
mid = (l + r) / 2;
build(l, mid, 2 * k);
build(mid + 1, r, 2 * k + 1);
}
void add(int i, int r, int x)
{
int mid;
if (t[i].r == t[i].l)
{
t[i].ls = t[i].rs = t[i].ms = x;
return;
}
mid = (t[i].r + t[i].l) / 2;
if (r <= mid)
add(2 * i, r, x);
else
add(2 * i + 1, r, x);
if (t[i * 2].ls == t[i * 2].r - t[i * 2].l + 1)
t[i].ls = t[i * 2].ls + t[i * 2 + 1].ls;
else
t[i].ls = t[i * 2].ls;
if (t[i * 2 + 1].rs == t[i * 2 + 1].r - t[i * 2 + 1].l + 1)
t[i].rs = t[i * 2 + 1].rs + t[i * 2].rs;
else
t[i].rs = t[i * 2 + 1].rs;
t[i].ms = max(max(t[i * 2].ms, t[i * 2 + 1].ms), t[i * 2].rs + t[i * 2 + 1].ls);
}
int findd(int k, int r)
{
int mid;
if (t[k].l == t[k].r || t[k].ms == 0 || t[k].ms == t[k].r - t[k].l + 1)
{
return t[k].ms;
}
mid = (t[k].r + t[k].l) / 2;
if (r <= mid)
{
if (r >= t[2 * k].r - t[2 * k].rs + 1)
return t[k * 2].rs + t[k * 2 + 1].ls;
else
return findd(2 * k, r);
}
else
{
if (r <= t[2 * k + 1].l + t[2 * k + 1].ls - 1)
return t[k * 2 + 1].ls + t[k * 2].rs;
else
return findd(2 * k + 1, r);
}
}
int main()
{
int n, m, a;
char str[10];
while(~scanf("%d%d", &n, &m))
{
build(1, n, 1);
stack<int>q;
if(!q.empty())
q.pop();
while (m--)
{
scanf("%s", str);
if (str[0] == 'D')
{
scanf("%d", &a);
q.push(a);
add(1, a, 0);
}
else if (str[0] == 'Q')
{
scanf("%d", &a);
printf("%d\n", findd(1, a));
}
else if (str[0] == 'R')
{
a = q.top();
q.pop();
add(1, a, 1);
}
}
}
return 0;
}