POJ 2155 Matrix 线段树解法

楼教主的二维线段树(树状数组)                ---------------这一题是真的不知道怎么做 ,但还是AC了...

题目我就不贴了...我就简单说一下题意:

1000*1000的矩阵,给你50000个操作

C操作 对从左上角(x1,y1)到右下角(x2,y2)的矩形中所有元素取反

Q操作 查询某坐标下元素的值

一看就是经典树状数组或者线段树了,大部分题解都很偷懒都是用二维树状数组的快速写法...

我在这里就用二维线段树来解了,不过线段树明显开销比树状数组大很多,线段树在结构体上要开4倍

这道题是二维因此比树状数组整整大了16倍,内存爆的很明显...

用int绝对MLE无误...于是我用了short竟然过了太意外...只能说数据比较水卡内存还没卡到变态程度...

线段树用的是自己写的模板...稍微修改一下处理二维处理区间和,区间极值都没问题


很经典的树套树...X轴(row)为母树,Y轴(column)为子树         ----------------其实随便怎么构建都行

对母线段树的每一个区间再构建一棵子线段树...每次更新的时候直接更新子树的值,查询同理...

母树不需要储存任何数据...只要构建起来为子树查询就行了

所以应该能用二维数组进行一个优化...这里我智商捉急暂时没想到快速的构建办法....(树状数组的那个方法简直太神了)

每个函数都要写两个真是坑爹死了...以至于太长写了4K...

/*Template*/
/*POJ 2155 */
/*52728 KB	1782 ms */ 
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <cassert>
#include <cctype>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
using namespace std;
//typedef long long LL;
//typedef __int64 LL;
//Number
#define EPS  1e-8
#define MAXN 1050
#define INF  (1<<30)
#define MOD  99991
//Math
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int lcm(int a,int b){return a*b/gcd(a,b);}
//Segment Tree
#define L(t) (t << 1)  //Left son
#define R(t) (t << 1 | 1) //Right son
#define mid(a,b) ((a+b)>>1) //Get Mid
//BIT
#define lowbit(a) (a&-a) //Get Lowbit
struct sub_node
{
	short l,r,val;
}sub_tree[MAXN*4][MAXN*4];
struct node //main tree
{
	short l,r;
}tree[MAXN*4];
void sub_build(int mroot,int l,int r,int root)  
{
	sub_tree[mroot][root].l=l;
	sub_tree[mroot][root].r=r;
	sub_tree[mroot][root].val=0;
	if(l==r) return ;
	int m=mid(l,r);
	sub_build(mroot,l,m,L(root));
	sub_build(mroot,m+1,r,R(root));
}
void build(int l,int r,int root)
{
	tree[root].l=l;
	tree[root].r=r; 
	sub_build(root,0,MAXN,1); 
	if(l==r) return ;	
	int m=mid(l,r);
	build(l,m,L(root));
	build(m+1,r,R(root));
}
void sub_modify(int mroot,int l,int r,int root,int val)
{
	if(sub_tree[mroot][root].l==l && sub_tree[mroot][root].r==r)
	{
		sub_tree[mroot][root].val+=val;
		return ;
	}
	int m = mid(sub_tree[mroot][root].l,sub_tree[mroot][root].r);
	if(r <= m)
		sub_modify(mroot,l,r,L(root),val);
	else if(l > m)
		sub_modify(mroot,l,r,R(root),val);
	else 
	{
		sub_modify(mroot,l,m,L(root),val);
		sub_modify(mroot,m+1,r,R(root),val);
	}
}
void modify(int l,int r,int ly,int ry,int root,int val)
{
	if(tree[root].l==l && tree[root].r==r)
	{
		sub_modify(root,ly,ry,1,val);
		return ;
	}
	int m = mid(tree[root].l,tree[root].r);
	if(r <= m)
		modify(l,r,ly,ry,L(root),val);
	else if(l > m)
		modify(l,r,ly,ry,R(root),val);
	else 
	{
		modify(l,m,ly,ry,L(root),val);
		modify(m+1,r,ly,ry,R(root),val);
	}
}
int sub_query(int mroot,int x,int root)
{
	if(sub_tree[mroot][root].l==sub_tree[mroot][root].r)
		return sub_tree[mroot][root].val;
	int m = mid(sub_tree[mroot][root].l,sub_tree[mroot][root].r);
	if(x <= m)
		return sub_tree[mroot][root].val+sub_query(mroot,x,L(root));
	else 
		return sub_tree[mroot][root].val+sub_query(mroot,x,R(root));
}
int query(int x,int y,int root)
{
	if(tree[root].l==tree[root].r)
		return sub_query(root,y,1);
	int m = mid(tree[root].l,tree[root].r);
	if(x <= m)
		return sub_query(root,y,1) + query(x,y,L(root));
	else 
		return sub_query(root,y,1) + query(x,y,R(root));
}
int main()
{
//	freopen("in.txt","r",stdin);
//  freopen("out.txt,"w",stdout);
	int n ;
	scanf("%d",&n);
	while(n--)
	{
		build(0,MAXN,1);
		int i,n,t;
		scanf("%d%d",&n,&t);
		for(i=0;i<t;i++)
		{
			getchar();
			char x;
			int a,b,c,d;
			scanf("%c",&x);
			if(x=='C')
			{				
				scanf("%d%d%d%d",&a,&b,&c,&d);
				modify(a,c,b,d,1,1);
			}
			else
			{
				scanf("%d%d",&a,&b);
				cout<<query(a,b,1)%2<<endl;
			}		
		}
		puts("");
	}
    return 0;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值