POJ 2155 Matrix【二维线段树】

题目:http://poj.org/problem?id=2155

题意:给一个N*N的全是0的矩阵,每次操作都是选一个子矩阵对其中每一项都取反。每次询问一个具体位置的值

分析:这题很明显的是个二维线段树模板题,但是在具体实现过程中由于一种是用延迟更新的做法导致了几次TLE。。以前从没遇到过用了延迟更新还会超时的情况,于是认真分析了一下,发现由于每次查询都一定查到叶子节点,所以延时更新完全没有作用,但是又不能每次更新都更新到叶子节点。再参考过discuss里面的代码之后,发现让所有节点之间都没有关系即不再使用线段树的区间和功能之后可以实现想利用了延迟更新一样的时间,这种方法是建立在操作是取反这种有循环节的操作上。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#define N 1005
using namespace std;
int tree[N<<2][N<<2];
int n,m,ans;

void inity(int cur,int l,int r,int id)
{
    tree[cur][id]=0;
    if(l==r)return ;
    int mid=(l+r)>>1;
    inity(cur,l,mid,id<<1);
    inity(cur,mid+1,r,id<<1|1);
}

void initx(int l,int r,int id)
{
    inity(id,1,n,1);
    if(l==r)return ;
    int mid=(l+r)>>1;
    initx(l,mid,id<<1);
    initx(mid+1,r,id<<1|1);
}

void queryy(int cur,int pos,int l,int r,int id)
{
    ans^=tree[cur][id];
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)queryy(cur,pos,l,mid,id<<1);
    else queryy(cur,pos,mid+1,r,id<<1|1);
}

void queryx(int cur,int pos,int l,int r,int id)
{
    queryy(id,pos,1,n,1);
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(cur<=mid)queryx(cur,pos,l,mid,id<<1);
    else queryx(cur,pos,mid+1,r,id<<1|1);
}

void updatay(int cur,int ql,int qr,int l,int r,int id)
{
    if(ql<=l&&r<=qr)
    {
        tree[cur][id]^=1;
        return ;
    }
    int mid=(l+r)>>1;
    if(ql<=mid)updatay(cur,ql,qr,l,mid,id<<1);
    if(qr>mid)updatay(cur,ql,qr,mid+1,r,id<<1|1);
}

void updatax(int qlx,int qrx,int qly,int qry,int l,int r,int id)
{
    if(qlx<=l&&r<=qrx)
    {
        updatay(id,qly,qry,1,n,1);
        return ;
    }
    int mid=(l+r)>>1;
    if(qlx<=mid)updatax(qlx,qrx,qly,qry,l,mid,id<<1);
    if(qrx>mid)updatax(qlx,qrx,qly,qry,mid+1,r,id<<1|1);
}

int main()
{
    int t;scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        initx(1,n,1);
        while(m--)
        {
            char c;cin>>c;
            if(c=='Q')
            {
                int x,y;scanf("%d%d",&x,&y);
                ans=0;
                queryx(x,y,1,n,1);
                printf("%d\n",ans);
            }
            else
            {
                int x1,x2,y1,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                updatax(x1,x2,y1,y2,1,n,1);
            }
        }
        if(t)printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值