二维线段树就是一维树X的每个结点都有另外一个线代树Y,存值仿照一维的。sum[x][rt]:X树的x结点里Y树的rt号结点的值。
单点的是第一维query/update在每个区间结点都query/update第二维且第二维在符合条件时更新
//单点
void subUpdate(int rt,int l,int r,int x,int Y,int num){
if(l == r && r == Y)
sum[x][rt] += num;
}
void update(int rt,int l,int r,int x,int y,int num){
subUpdate(1,1,n,rt,y,num);
}
区间的是在第一维的区间范围内才更新第二维,且第二维也在范围内才更新
//区间更新/查询
void subUpdate(int rt,int l,int r,int x,int Y1,int Y2,int num){ //第二维
if(Y1 <= l && r <= Y2)
sum[x][rt] ^= num;
}
void update(int rt,int l,int r,int X1,int Y1,int X2,int Y2,int num){ //第一维
if(X1 <= l && r <= X2)
subUpdate(1,1,n,rt,Y1,Y2,num);
}
单点更新,区间查询
POJ 1195 Mobile phones
一个二维矩阵初值为0,2个操作
1、某点(x,y)值增加val
2、查询子矩阵的和
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define rep( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof (a) );
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);
#define MOD 10009
#define bug(x) cout<<#x<<":"<<(x)<<endl;
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
const int maxn=1025;
const int inf = 0x3f3f3f3f;
ll sum[maxn*4][maxn*4];
int n;
void subBuild(int rt,int l,int r,int x){
sum[x][rt] = 0;
if(l != r){
int m = (l + r)>>1;
subBuild(lson,x);
subBuild(rson,x);
}
}
void build(int rt,int l,int r){
subBuild(1,1,n,rt);
if(l != r){
int m = (l + r)>>1;
build(lson);
build(rson);
}
}
void subUpdate(int rt,int l,int r,int x,int Y,int num){
if(l == r && r == Y){
sum[x][rt] += num;
}else{
int m = (l + r)>>1;
if(Y <= m)
subUpdate(lson,x,Y,num);
if(Y > m)
subUpdate(rson,x,Y,num);
sum[x][rt] = sum[x][rt<<1] + sum[x][rt<<1|1];
}
}
void update(int rt,int l,int r,int X,int Y,int num){
subUpdate(1,1,n,rt,Y,num);
if(l != r){
int m = (l + r)>>1;
if(X <= m)
update(lson,X,Y,num);
if(X > m)
update(rson,X,Y,num);
}
}
ll subQuery(int rt,int l,int r,int x,int Y1,int Y2){
if(Y1 <= l && r <= Y2){
return sum[x][rt];
}else{
int m = (l + r)>>1;
ll tmp = 0;
if(Y1 <= m)
tmp += subQuery(lson,x,Y1,Y2);
if(Y2 > m)
tmp += subQuery(rson,x,Y1,Y2);
return tmp;
}
}
ll query(int rt,int l,int r,int X1,int Y1,int X2,int Y2){
if(X1 <= l && r <= X2){
return subQuery(1,1,n,rt,Y1,Y2);
}else{
int m = (l + r)>>1;
ll tmp = 0;
if(X1 <= m)
tmp += query(lson,X1,Y1,X2,Y2);
if(X2 > m)
tmp += query(rson,X1,Y1,X2,Y2);
return tmp;
}
}
int main()
{
int op,X1,Y1,X2,Y2,num;
while(scanf("%d",&op)!=EOF){
if(op == 0){
scanf("%d",&n);
build(1,1,n+1);//+1
}else if(op == 1){
scanf("%d%d%d",&X1,&Y1,&num);
X1++,Y1++;
update(1,1,n,X1,Y1,num);
}else if(op == 2){
scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2);
X1++,Y1++,X2++,Y2++;
printf("%lld\n",query(1,1,n,X1,Y1,X2,Y2));
}else if(op == 3){
break;
}
}
return 0;
}
HDU 1823 Luck and Love
单点更新求最大值。数据是浮点的就根据题目数据特性乘个10就好了,X线段树的查找可以直接从100开始(还是题目数据),Y线段树要从0开始(数据从0开始)
数据中有身高活泼度相同 但是缘分值不同的情况,所以更新要max,而不是直接赋值
找BUG找半天,原来是query的X1,X2,Y1,Y2顺序与传进去的不同。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define rep( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof (a) );
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);
#define MOD 10009
#define bug(x) cout<<#x<<":"<<(x)<<endl;
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
const int maxn=202;
const int inf = 0x3f3f3f3f;
int sum[maxn*4][1002*4];
int n;
void subBuild(int rt,int l,int r,int x){
sum[x][rt] = -1;
if(l != r){
int m = (l + r)>>1;
subBuild(lson,x);
subBuild(rson,x);
}
}
void build(int rt,int l,int r){
subBuild(1,0,n,rt);
if(l != r){
int m = (l + r)>>1;
build(lson);
build(rson);
}
}
void subUpdate(int rt,int l,int r,int x,int Y,int num){
if(l == r && r == Y){
sum[x][rt] = max(num,sum[x][rt]); //>_<
}else{
int m = (l + r)>>1;
if(Y <= m)
subUpdate(lson,x,Y,num);
if(Y > m)
subUpdate(rson,x,Y,num);
sum[x][rt] = max(sum[x][rt<<1],sum[x][rt<<1|1]);
}
}
void update(int rt,int l,int r,int X,int Y,int num){
subUpdate(1,0,n,rt,Y,num);
if(l != r){
int m = (l + r)>>1;
if(X <= m)
update(lson,X,Y,num);
if(X > m)
update(rson,X,Y,num);
}
}
int subQuery(int rt,int l,int r,int x,int Y1,int Y2){
if(Y1 <= l && r <= Y2){
return sum[x][rt];
}else{
int m = (l + r)>>1;
int tmp = -1;
if(Y1 <= m)
tmp = max(tmp,subQuery(lson,x,Y1,Y2));
if(Y2 > m)
tmp = max(tmp,subQuery(rson,x,Y1,Y2));
return tmp;
}
}
int query(int rt,int l,int r,int X1,int X2,int Y1,int Y2){
if(X1 <= l && r <= X2){
return subQuery(1,0,n,rt,Y1,Y2);
}else{
int m = (l + r)>>1;
int tmp = -1;
if(X1 <= m)
tmp = max(tmp,query(lson,X1,X2,Y1,Y2));
if(X2 > m)
tmp = max(tmp,query(rson,X1,X2,Y1,Y2));
return tmp;
}
}
int main()
{
// RE
char op;
int m,H,H1,H2;
double A,L,A1,A2;
while(scanf("%d",&m)!=EOF,m){
n = 1000;
build(1,100,200);
while(m--){
scanf("%*c%c",&op);
if(op == 'I'){
scanf("%d%lf%lf",&H,&A,&L);
update(1,100,200,H,int(A*10),int(L*10));
}else if(op == 'Q'){
scanf("%d%d%lf%lf",&H1,&H2,&A1,&A2);
if(H1 > H2) swap(H1,H2);
if(A1 > A2) swap(A1,A2);
int ans = query(1,100,200,H1,H2,int(A1*10),int(A2*10));
if(ans == -1)
printf("-1\n");
else
printf("%.1f\n",(double)ans/10.0);
}
}
}
return 0;
}
POJ 2029 Get Many Persimmon Trees
在W,H的01矩阵里,找大小为S,T的子矩阵,要求子矩阵元素和最大,求和。
更新的操作里要 += ,不是直接赋值。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define rep( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof (a) );
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);
#define MOD 10009
#define bug(x) cout<<#x<<":"<<(x)<<endl;
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
const int maxn=105;
const int inf = 0x3f3f3f3f;
int sum[maxn*4][maxn*4];
int n;
void subBuild(int rt,int l,int r,int x){
sum[x][rt] = 0;
if(l != r){
int m = (l + r)>>1;
subBuild(lson,x);
subBuild(rson,x);
}
}
void build(int rt,int l,int r){
subBuild(1,1,n,rt);
if(l != r){
int m = (l + r)>>1;
build(lson);
build(rson);
}
}
void subUpdate(int rt,int l,int r,int x,int Y,int num){
if(l == r && r == Y){
sum[x][rt] += num; //!!!!!!多次覆盖
}else{
int m = (l + r)>>1;
if(Y <= m)
subUpdate(lson,x,Y,num);
if(Y > m)
subUpdate(rson,x,Y,num);
sum[x][rt] = sum[x][rt<<1] + sum[x][rt<<1|1];
}
}
void update(int rt,int l,int r,int X,int Y,int num){
subUpdate(1,1,n,rt,Y,num);
if(l != r){
int m = (l + r)>>1;
if(X <= m)
update(lson,X,Y,num);
if(X > m)
update(rson,X,Y,num);
}
}
int subQuery(int rt,int l,int r,int x,int Y1,int Y2){
if(Y1 <= l && r <= Y2){
return sum[x][rt];
}else{
int m = (l + r)>>1;
int tmp = 0;
if(Y1 <= m)
tmp += subQuery(lson,x,Y1,Y2);
if(Y2 > m)
tmp += subQuery(rson,x,Y1,Y2);
return tmp;
}
}
int query(int rt,int l,int r,int X1,int X2,int Y1,int Y2){
if(X1 <= l && r <= X2){
return subQuery(1,1,n,rt,Y1,Y2);
}else{
int m = (l + r)>>1;
int tmp = 0;
if(X1 <= m)
tmp += query(lson,X1,X2,Y1,Y2);
if(X2 > m)
tmp += query(rson,X1,X2,Y1,Y2);
return tmp;
}
}
// w为第一维大小,n为第二维的大小
int main()
{
// RE
int k,w,s,t,X1,Y1;
while(scanf("%d",&k)!=EOF,k){
scanf("%d%d",&w,&n);
memset(sum,0,sizeof(sum)); // build(1,1,w); 等价
while(k--){
scanf("%d%d",&X1,&Y1);
update(1,1,w,X1,Y1,1);
}
scanf("%d%d",&s,&t);
int ans = 0;
for(int i=1;i+s-1<=w;i++)
for(int j=1;j+t-1<=n;j++)
ans = max(ans,query(1,1,w,i,i+s-1,j,j+t-1));
printf("%d\n", ans);
}
return 0;
}
区间更新,单点查询
POJ 2155 Matrix
01矩阵,将子矩阵取反 或者 查询某点值。从根往下异或仿照lazy。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define rep( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof (a) );
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);
#define MOD 10009
#define bug(x) cout<<#x<<":"<<(x)<<endl;
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
const int maxn=1002;
const int inf = 0x3f3f3f3f;
int sum[maxn*4][maxn*4];
int n;
void subBuild(int rt,int l,int r,int x){
sum[x][rt] = 0;
if(l != r){
int m = (l + r)>>1;
subBuild(lson,x);
subBuild(rson,x);
}
}
void build(int rt,int l,int r){
subBuild(1,1,n,rt);
if(l != r){
int m = (l + r)>>1;
build(lson);
build(rson);
}
}
void subUpdate(int rt,int l,int r,int x,int Y1,int Y2,int num){
if(Y1 <= l && r <= Y2){
sum[x][rt] ^= num;
}else{
int m = (l + r)>>1;
if(Y1 <= m)
subUpdate(lson,x,Y1,Y2,num);
if(Y2 > m)
subUpdate(rson,x,Y1,Y2,num);
}
}
void update(int rt,int l,int r,int X1,int Y1,int X2,int Y2,int num){
if(X1 <= l && r <= X2)
subUpdate(1,1,n,rt,Y1,Y2,num);
else{
int m = (l + r)>>1;
if(X1 <= m)
update(lson,X1,Y1,X2,Y2,num);
if(X2 > m)
update(rson,X1,Y1,X2,Y2,num);
}
}
int ans;
void subQuery(int rt,int l,int r,int x,int X1,int Y1){
ans ^= sum[x][rt];
if(l != r){
int m = (l + r)>>1;
if(Y1 <= m)
subQuery(lson,x,X1,Y1);
if(Y1 > m)
subQuery(rson,x,X1,Y1);
}
}
void query(int rt,int l,int r,int X1,int Y1){
subQuery(1,1,n,rt,X1,Y1);
if(l != r){
int m = (l + r)>>1;
if(X1 <= m)
query(lson,X1,Y1);
if(X1 > m)
query(rson,X1,Y1);
}
}
int main()
{
// RE
int w,X1,Y1,X2,Y2,m,te;
char op;
scanf("%d",&te);
int cas = 0;
while(te--){
if(cas) puts("");
cas++;
scanf("%d%d",&n,&m);
build(1,1,n+1);//+1
while(m--){
scanf("%*c%c",&op);
if(op=='C'){
scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2);
update(1,1,n,X1,Y1,X2,Y2,1);
}else{
ans = 0;
scanf("%d%d",&X1,&Y1);
query(1,1,n,X1,Y1);
printf("%d\n", ans);
}
}
}
return 0;
}