【传送门】Tunnel Warfare
【题意】给定一个点求其所在最大连续区间的长度。
【方法】维护三个变量,
pre[i]表示线段树结点i所代表区间的最大连续前缀,
suf[i]表示线段树结点i所代表区间的最大连续后缀,
maxLen[i]表示线段树结点i所代表区间的最大连续区间长度。
【模板】
#include <iostream> #include <cstdio> #include <stack> #include <cmath> #include <algorithm> using namespace std; const int maxn = 50000 + 100; int n,q; int s[maxn<<2],e[maxn<<2]; int pre[maxn<<2], suf[maxn<<2], maxLen[maxn<<2]; void build(int rt, int l, int r){ s[rt] = l; e[rt] = r; pre[rt] = suf[rt] = maxLen[rt] = r - l + 1; int mid = (l + r) >> 1; if(l != r){ build(rt<<1 , l, mid); build(rt<<1|1, mid+1, r); } } void pushUp(int rt){ pre[rt] = pre[rt<<1]; suf[rt] = suf[rt<<1|1]; maxLen[rt] = max(maxLen[rt<<1] , maxLen[rt<<1|1]); maxLen[rt] = max(maxLen[rt] , suf[rt<<1] + pre[rt<<1|1]); if(pre[rt<<1] == e[rt<<1] - s[rt<<1] + 1) pre[rt] += pre[rt<<1|1]; if(suf[rt<<1|1] == e[rt<<1|1] - s[rt<<1|1] + 1) suf[rt] += suf[rt<<1]; } void update(int rt, int k, int v){ if(s[rt] == k && e[rt] == k){ pre[rt] = suf[rt] = maxLen[rt] = v; return ; } if(s[rt] == e[rt] ){ return ; } int mid = (s[rt] + e[rt]) >> 1; if(k > mid) update(rt<<1|1 , k , v); else update(rt<<1, k , v); pushUp(rt); } int query(int rt , int k){ if(maxLen[rt] == 0 || maxLen[rt] == e[rt] - s[rt] +1){ return maxLen[rt]; } int mid = (e[rt] + s[rt]) >> 1; if(k <= mid){ if( k >= e[rt<<1] - suf[rt<<1] + 1) return suf[rt<<1] + pre[rt<<1|1]; else query(rt<<1 , k); } else{ if(k <= s[rt<<1|1] + pre[rt<<1|1] - 1) return suf[rt<<1] + pre[rt<<1|1]; else query(rt<<1|1, k); } } int main(){ char op[2]; while(scanf("%d%d",&n,&q) != EOF){ build(1,1,n); stack<int> s; int x; while(q--){ scanf("%s",op); if(op[0] == 'D'){ scanf("%d",&x); update(1,x,0); s.push(x); } else if(op[0] == 'Q'){ scanf("%d",&x); printf("%d\n",query(1,x)); } else if(op[0] == 'R'){ x = s.top(); s.pop(); update(1,x,1); } } } return 0; }