题意:
1-n个地道,m个次操作,D代表摧毁第i个地道,Q代表查询包含第i个地道的最大连续地道数目,并输出。R代表修复最近摧毁的那个地道。

第二次写了,看到题目有大致的思路,但还是不知道具体怎么实现。

思路:
可以维护一个区间的左连续区间长度li[],以及右连续区间长度ri[]。如果左孩子区间整个区间是连续的,那么当前节点的左连续区间长度等于左孩子区间长度加右孩子的左连续区间长度;当前节点的右连续区间长度的求法一样。

难点在怎么去找第i个地道的最大连续地道数目。如果不在当前区间的左或者右连续区间,那么接着访问包含节点i的区间。如果i在当前节点的左或者右连续区间,且当前节点是根结点,那么答案就是这个左或者右连续区间的长度。如果当前节点不是根结点,如果i在当前节点的左连续区间,那么答案就是这个左连续区间的长度加上他左边区间的右连续长度。如果当前节点不是根结点,如果i在当前节点的右连续区间,那么答案就是这个右连续区间的长度加上他右边区间的左连续长度。
实现这个操作要用到线段树建图的“常识”,当前区间rt左边的区间下标是rt-1,右边区间下标是rt+1(不是有手就行),外围的区间除外。但在这题因为特判了根结点的情况,所以当该区间不是根区间时,不会出现i在最左边的区间的左连续区间里,或者最右边的区间的右连续区间里。

Code:

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
inline ll read() {
    ll s = 0, w = 1;
    char ch = getchar();
    while (ch < 48 || ch > 57) {
        if (ch == '-') w = -1;
        ch = getchar();
    }
    while (ch >= 48 && ch <= 57)
        s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}
int ri[maxn<<2],li[maxn<<2];
inline void build(int l,int r,int rt) {
    li[rt]=ri[rt]=r-l+1;
    if(l==r) return;
    int mid=l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
}
inline void update(int x,int val,int l,int r,int rt) {
    if(l==r) {
        li[rt]=ri[rt]=val;
        return;
    }
    int mid=l+r>>1;
    if(x<=mid) update(x,val,l,mid,rt<<1);
    else update(x,val,mid+1,r,rt<<1|1);
    if(ri[rt<<1|1]==r-mid) ri[rt]=r-mid+ri[rt<<1];
    else ri[rt]=ri[rt<<1|1];
    if(li[rt<<1]==mid-l+1) li[rt]=mid-l+1+li[rt<<1|1];
    else li[rt]=li[rt<<1];
}
inline int query(int x,int l,int r,int rt) {
    if(l==r) return 0;
    if(rt==1) {
        if(li[rt]>=x) return li[rt];
        if(r-ri[rt]+1<=x) return ri[rt];
    }
    if(l+li[rt]-1>=x) return li[rt]+ri[rt-1];
    if(r-ri[rt]+1<=x) return ri[rt]+li[rt+1];
    int mid=l+r>>1;
    if(x<=mid) query(x,l,mid,rt<<1);
    else query(x,mid+1,r,rt<<1|1);
}
int main() {
    char ch;
    int que[maxn],top,n,m,k;
    while(~scanf("%d%d",&n,&m)) {
        build(1,n,1);
        top=0;
        while(m--) {
            scanf(" %c",&ch);
            if(ch=='D') {
                k=read();
                que[++top]=k;
                update(k,0,1,n,1);
            }
            else if(ch=='Q') {
                k=read();
                printf("%d\n",query(k,1,n,1));
            }
            else {
                if(!top) continue;
                k=que[top--];
                update(k,1,1,n,1);
            }
        }
    }
    return 0;
}