pku2155 Matrix
这题的要求和树状数组的使用方法恰好相反,改变的是一个区间,查询的反而是一个点。我们先看一维的情况。
首先定义
Up(a)={a1=a,a2=a1+lowbit(a1),a3=a2+lowbit(a2) ... }
Down(a)={a1=a,a2=a1-lowbit(a1),a3=a2-lowbit(a2) ... }
为了方便讨论,只说明初始化后的第一次“C a b”和“Q c”操作:
对于命令“C a b”,我们分别调用函数down(b,1)和down(a-1,-1),将下标属于集合Down(b)的C中的元素+1,下标属于集合Down(a-1)的C中的元素-1,联系到通常树状数组的求和为down(b)-down(a-1),这里只不过把取值操作转变为对值的修改;
然后分情况讨论函数up(c)如何对点进行查询,可以发现对于任意的a<=b,Up(a)与Down(b)的交集只有一个元素。
因此
当a<c<=b时,Up(c)与Down(a-1)无交集,与Down(b)有交集且交集内只有一个元素,由之前的修改可知该元素为1,故返回1;
当b<c时,Up(c)与Down(b)无交集,故返回0;
当c<=a时,Up(c)分别与Down(b)和Down(a-1)构成一个元素的交集,其元素分别为-1和1,抵消后返回0;
此时返回值就是点c处的值。
了解如何获得第一次修改后的询问结果后,只要将简单的返回值变更为对下标属于集合Up(c)的C中元素的累加值,就能得到多次修改后的询问结果,然后扩展至二维即可。
/*
Source Code
Problem: 2155 User: zgmf_x20a
Memory: 4160K Time: 438MS
Language: C++ Result: Accepted
*/
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 1005
#define clr(x) memset(x,0,sizeof(x))
int c[MAXN][MAXN],n,query;
inline int lowbit(int x){
return x&(-x);
}
void down(int x,int y,int tt){
int i=x,j=y;
while(i>0){
j=y;
while(j>0){
c[i][j]+=tt;
j-=lowbit(j);
}
i-=lowbit(i);
}
}
int up(int x,int y){
int i=x,j=y,res=0;
while(i<=n){
j=y;
while(j<=n){
res+=c[i][j];
j+=lowbit(j);
}
i+=lowbit(i);
}
return res;
}
int main(){
int T,x1,y1,x2,y2;
char str[3];
scanf("%d",&T);
while(T--){
clr(c);
scanf("%d%d",&n,&query);
while(query--){
scanf("%s",str);
if(str[0]=='C'){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
down(x2,y2,1);
down(x1-1,y2,-1);
down(x2,y1-1,-1);
down(x1-1,y1-1,1);
}
else{
scanf("%d%d",&x1,&y1);
printf("%d\n",up(x1,y1)%2);
}
}
printf("\n");
}
return 0;
}
Source Code
Problem: 2155 User: zgmf_x20a
Memory: 4160K Time: 438MS
Language: C++ Result: Accepted
*/
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 1005
#define clr(x) memset(x,0,sizeof(x))
int c[MAXN][MAXN],n,query;
inline int lowbit(int x){
return x&(-x);
}
void down(int x,int y,int tt){
int i=x,j=y;
while(i>0){
j=y;
while(j>0){
c[i][j]+=tt;
j-=lowbit(j);
}
i-=lowbit(i);
}
}
int up(int x,int y){
int i=x,j=y,res=0;
while(i<=n){
j=y;
while(j<=n){
res+=c[i][j];
j+=lowbit(j);
}
i+=lowbit(i);
}
return res;
}
int main(){
int T,x1,y1,x2,y2;
char str[3];
scanf("%d",&T);
while(T--){
clr(c);
scanf("%d%d",&n,&query);
while(query--){
scanf("%s",str);
if(str[0]=='C'){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
down(x2,y2,1);
down(x1-1,y2,-1);
down(x2,y1-1,-1);
down(x1-1,y1-1,1);
}
else{
scanf("%d%d",&x1,&y1);
printf("%d\n",up(x1,y1)%2);
}
}
printf("\n");
}
return 0;
}
另附二维线段树代码
/*
Source Code
Problem: 2155 User: zgmf_x20a
Memory: 56440K Time: 1922MS
Language: C++ Result: Accepted
*/
#include <iostream>
using namespace std;
#define MAXN 1001
#define clr(x) memset(x,0,sizeof(x))
int n,m;
struct Node{
int l,r,cnt;
};
class SegTree{
Node nod[3*MAXN];
public:
void BuildTree(int u,int l,int r){
nod[u].l=l;
nod[u].r=r;
nod[u].cnt=0;
if(l==r)
return;
BuildTree(2*u,l,(l+r)/2);
BuildTree(2*u+1,(l+r)/2+1,r);
}
void Insert(int u,int l,int r){
if(l<=nod[u].l && nod[u].r<=r){
nod[u].cnt++;
return;
}
if(l<=nod[2*u].r)
Insert(2*u,l,r);
if(r>=nod[2*u+1].l)
Insert(2*u+1,l,r);
}
int Query(int u,int l,int r,int sum){
sum+=nod[u].cnt;
if(l<=nod[u].l && nod[u].r<=r)
return sum;
int res=0;
if(l<=nod[2*u].r)
res+=Query(2*u,l,r,sum);
if(r>=nod[2*u+1].l)
res+=Query(2*u+1,l,r,sum);
return res;
}
};
struct _2DNode{
SegTree tre;
//二维线段树中每个区间被翻转的次数用一维线段树统计
int l,r;
};
class _2DSegTree{
_2DNode _2Dnod[3*MAXN];
public:
void _2DBuildTree(int u,int xl,int xr,int yl,int yr){
_2Dnod[u].l=xl;
_2Dnod[u].r=xr;
_2Dnod[u].tre.BuildTree(1,yl,yr);
if(xl==xr)
return;
_2DBuildTree(2*u,xl,(xl+xr)/2,yl,yr);
_2DBuildTree(2*u+1,(xl+xr)/2+1,xr,yl,yr);
}
void _2DInsert(int u,int xl,int xr,int yl,int yr){
if(xl<=_2Dnod[u].l && _2Dnod[u].r<=xr){
_2Dnod[u].tre.Insert(1,yl,yr);
return;
}
if(xl<=_2Dnod[2*u].r)
_2DInsert(2*u,xl,xr,yl,yr);
if(xr>=_2Dnod[2*u+1].l)
_2DInsert(2*u+1,xl,xr,yl,yr);
}
int _2DQuery(int u,int xl,int xr,int yl,int yr,int sum){
sum+=_2Dnod[u].tre.Query(1,yl,yr,0);
if(xl<=_2Dnod[u].l && _2Dnod[u].r<=xr)
return sum;
int res=0;
if(xl<=_2Dnod[2*u].r)
res+=_2DQuery(2*u,xl,xr,yl,yr,sum);
if(xr>=_2Dnod[2*u+1].l)
res+=_2DQuery(2*u+1,xl,xr,yl,yr,sum);
return res;
}
};
_2DSegTree tr;
int main(){
int i,T,xl,xr,yl,yr;
char str[3];
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
tr._2DBuildTree(1,1,n,1,n);
for(i=0;i<m;i++){
scanf("%s",str);
if(str[0]=='C'){
scanf("%d%d%d%d",&xl,&yl,&xr,&yr);
tr._2DInsert(1,xl,xr,yl,yr);
}
else{
scanf("%d%d",&xl,&yl);
printf("%d\n",tr._2DQuery(1,xl,xl,yl,yl,0)%2);
}
}
printf("\n");
}
return 0;
}
Source Code
Problem: 2155 User: zgmf_x20a
Memory: 56440K Time: 1922MS
Language: C++ Result: Accepted
*/
#include <iostream>
using namespace std;
#define MAXN 1001
#define clr(x) memset(x,0,sizeof(x))
int n,m;
struct Node{
int l,r,cnt;
};
class SegTree{
Node nod[3*MAXN];
public:
void BuildTree(int u,int l,int r){
nod[u].l=l;
nod[u].r=r;
nod[u].cnt=0;
if(l==r)
return;
BuildTree(2*u,l,(l+r)/2);
BuildTree(2*u+1,(l+r)/2+1,r);
}
void Insert(int u,int l,int r){
if(l<=nod[u].l && nod[u].r<=r){
nod[u].cnt++;
return;
}
if(l<=nod[2*u].r)
Insert(2*u,l,r);
if(r>=nod[2*u+1].l)
Insert(2*u+1,l,r);
}
int Query(int u,int l,int r,int sum){
sum+=nod[u].cnt;
if(l<=nod[u].l && nod[u].r<=r)
return sum;
int res=0;
if(l<=nod[2*u].r)
res+=Query(2*u,l,r,sum);
if(r>=nod[2*u+1].l)
res+=Query(2*u+1,l,r,sum);
return res;
}
};
struct _2DNode{
SegTree tre;
//二维线段树中每个区间被翻转的次数用一维线段树统计
int l,r;
};
class _2DSegTree{
_2DNode _2Dnod[3*MAXN];
public:
void _2DBuildTree(int u,int xl,int xr,int yl,int yr){
_2Dnod[u].l=xl;
_2Dnod[u].r=xr;
_2Dnod[u].tre.BuildTree(1,yl,yr);
if(xl==xr)
return;
_2DBuildTree(2*u,xl,(xl+xr)/2,yl,yr);
_2DBuildTree(2*u+1,(xl+xr)/2+1,xr,yl,yr);
}
void _2DInsert(int u,int xl,int xr,int yl,int yr){
if(xl<=_2Dnod[u].l && _2Dnod[u].r<=xr){
_2Dnod[u].tre.Insert(1,yl,yr);
return;
}
if(xl<=_2Dnod[2*u].r)
_2DInsert(2*u,xl,xr,yl,yr);
if(xr>=_2Dnod[2*u+1].l)
_2DInsert(2*u+1,xl,xr,yl,yr);
}
int _2DQuery(int u,int xl,int xr,int yl,int yr,int sum){
sum+=_2Dnod[u].tre.Query(1,yl,yr,0);
if(xl<=_2Dnod[u].l && _2Dnod[u].r<=xr)
return sum;
int res=0;
if(xl<=_2Dnod[2*u].r)
res+=_2DQuery(2*u,xl,xr,yl,yr,sum);
if(xr>=_2Dnod[2*u+1].l)
res+=_2DQuery(2*u+1,xl,xr,yl,yr,sum);
return res;
}
};
_2DSegTree tr;
int main(){
int i,T,xl,xr,yl,yr;
char str[3];
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
tr._2DBuildTree(1,1,n,1,n);
for(i=0;i<m;i++){
scanf("%s",str);
if(str[0]=='C'){
scanf("%d%d%d%d",&xl,&yl,&xr,&yr);
tr._2DInsert(1,xl,xr,yl,yr);
}
else{
scanf("%d%d",&xl,&yl);
printf("%d\n",tr._2DQuery(1,xl,xl,yl,yl,0)%2);
}
}
printf("\n");
}
return 0;
}