题字:有n个连续村庄D代表破坏村庄,R代表修复一个被破坏的村庄,Q代表询问包括x在内的最大连续村庄是的长度
思路:在线段树的区间内,我们要用三个变量记录l开始的连续区间长度r截至的连续区间长度lr区间内最大连续区间长度
更新时最大区间长度等于左右区间的最大连续区间的最大值与右子树的左连续区间+左子树的右连续区间的最大值
查询时注意查询节点左右区间分界处的连续区间内
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
#define N 1000100
struct node
{
LL l;
LL r;
LL lm; // l开始的 连续区间长度
LL rm; // r截至的 连续区间长度
LL mm; // l-r 区间内最大连续区间长度
}tree[N << 2];
LL used[N]; //模拟栈
inline LL max(LL a, LL b, LL c)
{
a = a > c ? a : c;
return a > b ? a : b;
}
void build(LL root, LL l, LL r)
{
tree[root].l = l;
tree[root].r = r;
tree[root].lm = r - l + 1; //初始化村庄都是好的 所以 右、左、最大连续区间长度为区间长度
tree[root].rm = r - l + 1;
tree[root].mm = r - l + 1;
if (l == r) { return; }
LL mid = (l + r) / 2;
build(root * 2, l, mid);
build(root * 2 + 1, mid + 1, r);
}
void update(LL root, LL pos, LL val)
{
if (tree[root].l == tree[root].r)
{
tree[root].lm = val;
tree[root].rm = val;
tree[root].mm = val;
return;
}
int mid = (tree[root].l + tree[root].r) / 2;
if (pos <= mid)
{
update(root * 2, pos, val);
}
if (pos > mid)
{
update(root * 2 + 1, pos, val);
}
tree[root].lm = tree[root * 2].lm;
tree[root].rm = tree[root * 2 + 1].rm;
tree[root].mm = max(tree[root * 2].mm, tree[root * 2 + 1].mm, tree[root * 2].rm + tree[root * 2 + 1].lm); //最大区间长度等于 左右区间的最大连续区间的最大值 与 右子树的左连续区间+左子树的右连续区间 的最大值
if (tree[root * 2].lm == (tree[root * 2].r - tree[root * 2].l + 1)) //假如右子树的区间是满的话 那么更新后父亲节点可以延长到左子树的右连续区间
{
tree[root].lm += tree[root * 2 + 1].lm;
}
if (tree[root * 2 + 1].rm == (tree[root * 2 + 1].r - tree[root * 2 + 1].l + 1)) //同理
{
tree[root].rm += tree[root * 2].rm;
}
}
LL query(LL root, LL pos)
{
if (tree[root].mm == 0 || tree[root].l == tree[root].r || tree[root].mm == (tree[root].r - tree[root].l + 1)) // 叶子节点返回 (区间全空、全满返回 优化时间)
{
return tree[root].mm;
}
int mid = (tree[root].l + tree[root].r) / 2;
if (pos <= mid)
{
if (pos >= (tree[root * 2].r - tree[root * 2].rm + 1)) //判断pos位置是否在右子树的左连续区间上 tree[root * 2].r - tree[root * 2].rm + 1 代表右子树的左连续区间开始位置 如果是则 左子树的右连续区间可以增加到ans上
{
return query(root * 2, pos) + query(root * 2 + 1, mid + 1);
}
else
{
return query(root * 2, pos);
}
}
if (pos > mid)
{
if (pos <= (tree[root * 2 + 1].l + tree[root * 2 + 1].lm - 1)) //同理
{
return query(root * 2 + 1, pos) + query(root * 2, mid);
}
else
{
return query(root * 2 + 1, pos);
}
}
}
int main()
{
LL n, m, i, x, y, k; //k为栈的指针
char f[10];
while (scanf("%lld%lld", &n, &m) != EOF)
{
build(1, 1, n);
k = 1;
memset(used, 0, sizeof(used));
while (m--)
{
scanf("%s", f);
if (f[0] == 'D')
{
scanf("%lld", &x);
used[k++] = x;
update(1, x, 0);
}
if (f[0] == 'R')
{
x = used[--k];
update(1, x, 1);
}
if (f[0] == 'Q')
{
scanf("%lld", &y);
printf("%lld\n", query(1, y));
}
}
}
return 0;
}