hdu 1540


题意:1-n个地道,m个次操作,D代表摧毁第i个地道,Q代表查询包含第i个地道的最大连续地道数目,并输出。R代表修复最近摧毁的那个地道。
思路
(线段树&区间合并&最大连续区间)
充分利用了线段树相邻结点之间的区间都是连续的性质,x[rt]表示这个区间从左边起的连续区间的长度,y[rt]表示这个区间从右边起的连续区间的长度。
1.单点修改、区间合并,巧妙的地方是这一个区间的左连续区间x[rt]等于左孩子的长度加上右孩子的左连续区间(前提是左孩子的左连续区间x[rt<<1]等于左孩子的区间长度,也就是左孩子没有遭到破坏,反之x[rt]=x[rt<<1]),右孩子也是同样的道理。最基础的部分就是如果隧道被毁,就把只含这个隧道的区间赋值0,修复了就赋值1.
2.最大连续区间,先保证要求的隧道在该区间的左或右端点的连续区间内,如果不在左右某个连续区间内就查找子树。左右连续区间含该隧道的这一层,该隧道的最大连续区间(如果该隧道在该区间左连续区间上,如果是在该区间的右连续区间上也是一样算的)长度等于该区间的左连续长度加上左边区间的右连续长度。这里注意特判一下区间是根区间的情况,因为根区间没有左右兄弟区间。
Code

#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
template <class T>
inline void read(T &res) {
    char c; T flag = 1;
    while ((c = getchar()) < '0' || c > '9')
        if (c == '-')
            flag = -1;
    res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9')
        res = res * 10 + c - '0';
    res *= flag;
}
int sum[50001<<2],x[50001<<2],y[50001<<2];
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
void build(int l,int r,int rt) {
    x[rt]=y[rt]=r-l+1;//初始时rt区间从左边开始和从右边开始的连续区间都是r-l+1 
    if(l==r) return;
    int mid=l+r>>1;
    build(lson);
    build(rson);
}//初始化,全部的隧道都是联通的 
void add(int a,int c,int l,int r,int rt) {
    if(l==r) {
        x[rt]=y[rt]=c;
        return;
    }//c==0表示隧道破坏,c==1表示隧道修复。 
    int mid=l+r>>1;
    if(a<=mid) add(a,c,lson);
    else add(a,c,rson);
    if(x[rt<<1]==mid-l+1)
        x[rt]=mid-l+1+x[rt<<1|1];
    else x[rt]=x[rt<<1];
    if(y[rt<<1|1]==r-mid)
        y[rt]=r-mid+y[rt<<1];
    else y[rt]=y[rt<<1|1];
}
int query(int a,int l,int r,int rt) {
    if(rt==1) {
        if(x[rt]>=a) {
            return x[rt];
        }
        if(r-y[rt]+1<=a) {
            return y[rt];
        }
    }
    if(l+x[rt]-1>=a) {
        return x[rt]+y[rt-1];
    }
    if(r-y[rt]+1<=a) {
        return y[rt]+x[rt+1];
    }
    if(l==r)    return 0;
    int mid=l+r>>1;
    if(a<=mid) return query(a,lson);
    else return query(a,rson);
}
int n,m,k;
char ch;
stack<int>s;
int main() {
    while(~scanf("%d%d",&n,&m)) {
        build(1,n,1);
        while(!s.empty())    s.pop();
        while(m--) {
            scanf(" %c",&ch);
            if(ch=='D') {
                read(k);
                s.push(k);
                add(k,0,1,n,1);
            }
            else if(ch=='Q') {
                read(k);
                printf("%d\n",query(k,1,n,1));
            }
            else {
                if(s.empty()) continue;
                k=s.top();    s.pop();
                add(k,1,1,n,1);
            }
        }
    }
    return 0;
}

图片说明


poj 2155


题意:给一个空的二维矩阵,初始元素为0,有两种操作,C x1 y1 x2 y2将左上角到右下角的所有数反转一下,即0变1,1变0,Q x1 y1 ,询问当前坐标的值。题目给了t组数据,要求两组数据之间空一行。
思路:又是二维线段树,涉及到了区间的简单修改,和求单个点的值,所以不需要lazy操作。线段树结点保存的是更新的次数,奇数次为1,偶数次为0,修改[x,y](这里讨论的是行,列也是一样的)区间时,如果当前区间是[x,y]的子区间,更新这里就好了,如果该区间和[x,y]相交,就查询这个区间的子区间。查询某个点的值时,只要加上根到这个结点路径上的全部值,然后如果值是奇数,这个点就是1,反之是0,因为我们修改区间并没有深入更深的子区间。
Code

#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
template <class T>
inline void read(T &res) {
    char c; T flag = 1;
    while ((c = getchar()) < '0' || c > '9')
        if (c == '-')
            flag = -1;
    res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9')
        res = res * 10 + c - '0';
    res *= flag;
}
int sum[1005<<2][1005<<2],n,ans;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
void subupdate(int a,int b,int l,int r,int rt,int t) {
    if(a<=l&&b>=r) {
        sum[t][rt]^=1;
        return;
    }
    int mid=l+r>>1;
    if(a<=mid) subupdate(a,b,lson,t);
    if(b>mid) subupdate(a,b,rson,t);
}
void update(int x1,int x2,int y1,int y2,int l,int r,int rt) {
    if(x1<=l&&x2>=r) {
        subupdate(y1,y2,1,n,1,rt);
        return;
    }
    int mid=l+r>>1;
    if(x1<=mid)    update(x1,x2,y1,y2,lson);
    if(x2>mid) update(x1,x2,y1,y2,rson);
}
void subquery(int a,int l,int r,int rt,int t) {
    ans+=sum[t][rt];
    if(l==r) return;
    int mid=l+r>>1;
    if(a<=mid) subquery(a,lson,t);
    else  subquery(a,rson,t);
}
void query(int x,int y,int l,int r,int rt) {
    subquery(y,1,n,1,rt);
    if(l==r)    return;
    int mid=l+r>>1;
    if(x<=mid)    query(x,y,lson);
    else    query(x,y,rson);
}
char ch;
int t,m;
int main() {
    read(t);
    while(t--) {
        int x1,x2,y1,y2;
        read(n),read(m);
        memset(sum,0,sizeof sum);
        while(m--) {
            scanf(" %c",&ch);
            if(ch=='C') {
                read(x1),read(y1),read(x2),read(y2);
                update(x1,x2,y1,y2,1,n,1);
            }
            else {
                read(x1),read(y1);
                ans=0;
                query(x1,y1,1,n,1);
                if(ans&1) puts("1");
                else puts("0");
            }
        }
        if(t)    puts("");
    }
    return 0;
}