POJ 2155 Matrix 二维线段树+标记永久化?

题意:链接

方法:二维线段树+标记永久化

解析:题意是比较明朗的,算一下内存发现4000^2也是可以接受的,于是就开始yy二维线段树?

对于第一层x的线段树,每个节点开一整棵y线段树。

用个二维数组就实现了?

不过发现个问题啊,这题怎么pushdown啊,标记传不下去啊。如果给x打个标记那么怎么知道y传那段啊?

于是就学了新的东西?标记永久化。

本题是单点查询嘛,标记永久化就应该是把相应的区间直接异或,不用往下传?那查询的时候怎么办呢?只需要在查询的时候把所有路过该点的区间都异或起来就OK了。貌似也挺简单的样子?

难道标记永久化的适用就是在标记打不下去的时候?貌似吧。

另外这题有坑,不同组数据间有换行,为此还PE了一次。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define N 1010
using namespace std;
int t,n,q,ans;
char s[5];
int sum[N<<2][N<<2];
void update2(int L,int R,int l,int r,int rtx,int rty)
{
    if(L<=l&&r<=R)
    {
        sum[rtx][rty]^=1;
        return;
    }
    int mid=(l+r)>>1;
    if(L>mid)update2(L,R,mid+1,r,rtx,rty<<1|1);
    else if(R<=mid)update2(L,R,l,mid,rtx,rty<<1);
    else
    {
        update2(L,mid,l,mid,rtx,rty<<1);
        update2(mid+1,R,mid+1,r,rtx,rty<<1|1);
    }
}
void update(int x1,int x2,int y1,int y2,int l,int r,int rt)
{
    if(x1<=l&&r<=x2)
    {
        update2(y1,y2,1,n,rt,1);
        return;
    }
    int mid=(l+r)>>1;
    if(x1>mid)update(x1,x2,y1,y2,rson);
    else if(x2<=mid)update(x1,x2,y1,y2,lson);
    else
    {
        update(x1,mid,y1,y2,lson);
        update(mid+1,x2,y1,y2,rson);
    }
}
void query2(int y1,int l,int r,int rtx,int rty)
{
    ans^=sum[rtx][rty];
    if(l==r)
    {
        return;
    }
    int mid=(l+r)>>1;
    if(y1<=mid)query2(y1,l,mid,rtx,rty<<1);
    else query2(y1,mid+1,r,rtx,rty<<1|1);
}
void query(int x1,int y1,int l,int r,int rt)
{
    query2(y1,1,n,rt,1);
    if(l==r)
    {
        return;
    }
    int mid=(l+r)>>1;
    if(x1<=mid)query(x1,y1,l,mid,rt<<1);
    else query(x1,y1,mid+1,r,rt<<1|1);
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(sum,0,sizeof(sum));
        scanf("%d%d",&n,&q);
        for(int i=1;i<=q;i++)
        {
            scanf("%s",s);
            if(s[0]==‘C‘)
            {
                int x1,y1,x2,y2;
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                update(x1,x2,y1,y2,1,n,1);
            }else
            {
                ans=0;
                int x1,y1;
                scanf("%d%d",&x1,&y1);
                query(x1,y1,1,n,1);
                printf("%d\n",ans);
            }
        }
        printf("\n");
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-22 15:23:01

POJ 2155 Matrix 二维线段树+标记永久化?的相关文章

POJ 2155 Matrix (二维线段树)

http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 18143   Accepted: 6813 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. I

【BZOJ1513】【POI2006】Tet-Tetris 3D 二维线段树+标记永久化

题解:题意很裸啊~~~ 培训的时候说要写标记永久化,反正永久化很水,就直接写了. 但是我并不知道为什么要永久化,或者说理解不深刻,但是再遇上肯定能分析出来233. 大概应该可能或许就是: 直接原因:下传标记传不下去. 根本原因: 线段树有两层,这样它的传递可能就有点像拓扑了 就是外层线段树需要往内层线段树传,然后内层线段树还要下传 这样扫到某处时发现,****,还需要顺着两边的标记路径回溯到根, 然后各种压栈啊什么的,才能传下去,而且大概率出错(代码错或思路错). 所以简简单单写个标记永久化好了

poj2155 Matrix 二维线段树

二维线段树区间更新和单点查询,由于二维线段树不能传递标记,所以区间更新和一维不太一样,需要用到被更新的值以及更新操作的一些性质,还有要注意对query的影响. 这里操作是翻转,而且是单点查询,所以就直接在矩形块内更新,不把标记传递下去,查询的时候做一下微调,把所有经过的路径的标记都判断一遍,看是否需要翻转,这样就解决了这道题. 上一道是单点更新和区间求和,当然就不用标记了,把所有的第一维的第二层的y点全部更新,查询的时候不用查到最底层也能查到了. 二维线段树还是比较灵活,但这已经是最简单的树套树

POJ2155 Matrix二维线段树经典题

题目链接 二维树状数组 1 #include<iostream> 2 #include<math.h> 3 #include<algorithm> 4 #include<stdlib.h> 5 using namespace std; 6 #define ll long long 7 #define re(i,n) for(int i=0;i<n;i++) 8 const int maxn = 1007; 9 int c[maxn][maxn]; 10

POJ - 2155 Matrix (二维树状数组 + 区间改动 + 单点求值 或者 二维线段树 + 区间更新 + 单点求值)

POJ - 2155 Matrix Time Limit: 3000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we ha

POJ 2155 Matrix 二维树状数组

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 19174   Accepted: 7207 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ 2155 Matrix(二维树状数组,绝对具体)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ 2155 Matrix(二维树状数组,绝对详细)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ2155 Matrix二维线段树

一,题意: 给你一个全为0的N * N的矩阵,对这个矩阵有两个操作(对于矩阵只有两个状态0,1) (1):"C x1,y1,x2,y2"   就是将左上角为x1,y1,右下角为x2,y2,的这个矩阵内的数字全部翻转. (2):"Q x1 y1"   输出a[x1][y1]的值. 二,解析: 该我主要应用令二位的树状数组,一个是行,一个是列. 三,代码: #include<iostream> #include<cstdio> #include