题目大意
给定一个长度为n的全部为1的序列,可以对其进行以下三种操作:
1、D x 把第x个元素修改为0
2、Q x 查询包含第x个元素的全部为1的最长连续序列长度
3、R: 把最后一次修改的元素还原为1
题解
比较水的区间合并问题~~O(∩_∩)O~~。维护两个域即可,即包含节点左端的全部为1的最长连续序列长度lsum,包含节点右端的全部为1的最长连续序列长度rsum,对于某个查询,假设m为节点的中间位置,如果m-rsum[s<<1]+1<=x&&x<=m+lsum[s<<1|1](s为节点编号),则rsum[s<<1]+lsum[s<<1|1]就是查询的结果
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 50005 #define lson l,m,s<<1 #define rson m+1,r,s<<1|1 int lsum[MAXN<<2],rsum[MAXN<<2],a[MAXN]; void PushUp(int s,int m) { lsum[s]=lsum[s<<1]; rsum[s]=rsum[s<<1|1]; if(lsum[s<<1]==(m-(m>>1))) lsum[s]+=lsum[s<<1|1]; if(rsum[s<<1|1]==(m>>1)) rsum[s]+=rsum[s<<1]; } void build(int l,int r,int s) { lsum[s]=rsum[s]=r-l+1; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void update(int p,int d,int l,int r,int s) { if(l==r) { lsum[s]=rsum[s]=d; return; } int m=(l+r)>>1; if(p<=m) update(p,d,lson); else update(p,d,rson); PushUp(s,r-l+1); } int query(int p,int l,int r,int s) { if(l==r) return lsum[s]; int m=(l+r)>>1; if(m-rsum[s<<1]+1<=p&&p<=m+lsum[s<<1|1]) return rsum[s<<1]+lsum[s<<1|1]; if(p<=m) return query(p,lson); else return query(p,rson); } int main(void) { int n,m,p,len; char op[5]; while(scanf("%d%d",&n,&m)!=EOF) { len=0; build(1,n,1); while(m--) { scanf("%s",op); if(op[0]=='D') { scanf("%d",&p); update(p,0,1,n,1); a[len++]=p; } else if(op[0]=='R') { update(a[len-1],1,1,n,1); len--; } else { scanf("%d",&p); printf("%d\n",query(p,1,n,1)); } } } return 0; }