Problem(Description)
现在有一个长度为\(n\)的序列和\(m\)个操作,操作有两种:
- \(1,d\) 寻找到最左边的连续\(d\)个\(0\)的序列,并全部变成\(1\)。
- \(2,x,d\) 将\([x,x + d - 1]\)块全部变成\(0\)。\(1 \le n,m \le 50000\)
Solution
Thinking 1
其实这个题就两个东西:
- 找到最左边的长度不小于\(d\)的最长\(0\)块
- 区间修改
显然2可以用线段树做,1怎么做呢?
Thinking 2
想到洛谷 P4513 小白逛公园这一题,通过维护左边最长段,右边最长段和总最长段来确定,那么连续\(0\)块是不是也能这么做?
Thinking 3
设\(T[root].lmax\)为当前左边最长段,\(T[root].rmax\)同理,\(T[root].Max\)为总最长段。
在update时,如果是被完全包含的情况,若是add,那么三者全部变为0,否则全部变为这个节点的长度。
在pushdown的时候基本差不多,具体看代码。
pushup就是分别考虑更新当前节点的lmax,rmax和Max:
lmax:若左节点全部是0,那么lmax = l.Max + r.lmax; 否则lmax = l.lmax;
rmax:若右节点全部是0,那么rmax = r.Max + l.rmax; 否则rmax = r.rmax;
Max: 形如小白逛公园,Max = max(l.Max.r.Max,l.rmax + r.lmax);
然后query时根据情况二分即可。
# include <bits/stdc++.h>
using namespace std;
const int N = 50005;
int n,m;
struct node
{
int val,lazy;
int lmax,rmax,Max;
}T[N << 2];
void build(int root,int l,int r)
{
if(l == r)
{
T[root].val = T[root].lazy = 0,T[root].lmax = T[root].rmax = T[root].Max = 1;
return;
}
int mid = (l + r) >> 1;build(root << 1,l,mid),build(root << 1 | 1,mid + 1,r);
T[root].val = T[root << 1].val + T[root << 1 | 1].val,T[root].lmax = T[root].rmax = T[root].Max = (r - l + 1);
return;
}
void pushdown(int root,int l,int r)
{
if(T[root].lazy == 0) return;
int mid = (l + r) >> 1;
if(T[root].lazy == -1)
{
T[root << 1].lmax = T[root << 1].rmax = T[root << 1].Max = (mid - l + 1);
T[root << 1 | 1].lmax = T[root << 1 | 1].rmax = T[root << 1 | 1].Max = (r - mid);
T[root << 1].lazy = T[root << 1 | 1].lazy = -1;
}
else if(T[root].lazy == 1)
{
T[root << 1].lmax = T[root << 1].rmax = T[root << 1].Max = T[root << 1 | 1].lmax = T[root << 1 | 1].rmax = T[root << 1 | 1].Max = 0;
T[root << 1].lazy = T[root << 1 | 1].lazy = 1;
}
T[root].lazy = 0;return;
}
void pushup(int root,int l,int r)
{
int mid = (l + r) >> 1;
if(T[root << 1].Max == (mid - l + 1)) // full 0
{
T[root].lmax = T[root << 1].Max + T[root << 1 | 1].lmax;
}
else T[root].lmax = T[root << 1].lmax;
if(T[root << 1 | 1].Max == (r - mid))
{
T[root].rmax = T[root << 1 | 1].Max + T[root << 1].rmax;
}
else T[root].rmax = T[root << 1 | 1].rmax;
T[root].Max = max(T[root << 1].Max,max(T[root << 1 | 1].Max,T[root << 1].rmax + T[root << 1 | 1].lmax));
return;
}
void update(int root,int l,int r,int s,int t,int d)
{
if(l <= s && t <= r)
{
if(d == 1) T[root].lmax = T[root].rmax = T[root].Max = 0;
else T[root].lmax = T[root].rmax = T[root].Max = t - s + 1;
T[root].lazy = d;
return;
}
int mid = (s + t) >> 1;
pushdown(root,s,t);
if(l <= mid) update(root << 1,l,r,s,mid,d);
if(r > mid) update(root << 1 | 1,l,r,mid + 1,t,d);
pushup(root,s,t);
return;
}
int query(int root,int l,int r,int d)
{
pushdown(root,l,r);
// pushup(root,l,r);
if(l == r) return l;
int mid = (l + r) >> 1;
if(T[root << 1].Max >= d)
{
return query(root << 1,l,mid,d);
}
if(T[root << 1].rmax + T[root << 1 | 1].lmax >= d)
{
return mid - T[root << 1].rmax + 1;
}
else return query(root << 1 | 1,mid + 1,r,d);
}
int main(void)
{
scanf("%d%d",&n,&m);
build(1,1,n);
while(m--)
{
int d,x;
int opt;scanf("%d",&opt);
if(opt == 1)
{
scanf("%d",&d);
if(T[1].Max >= d)
{
x = query(1,1,n,d);
printf("%d\n",x);
update(1,x,x + d - 1,1,n,1);
}
else printf("%d\n",0);
}
else
{
scanf("%d%d",&x,&d);
update(1,x,x + d - 1,1,n,-1);
}
}
return 0;
}