「NOI2012」魔幻棋盘 - 二维线段树+二阶差分 | Bill Yang's Blog
0%

「NOI2012」魔幻棋盘 - 二维线段树+二阶差分

题目大意


题目分析

大家一起%Po姐


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<climits>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

typedef long long LL;

inline const LL Get_Int() {
LL num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

const int maxn=500005;

struct Segment_Tree_in {
struct Tree {
int lson,rson;
int left,right;
LL val;
Tree(int l=0,int r=0,LL x=0):left(l),right(r),val(x) {lson=rson=0;}
} tree[maxn<<4];
int size;
#define ls tree[index].lson
#define rs tree[index].rson
int build(int Left,int Right,vector<LL>& a) {
int index=++size;
tree[index]=Tree(Left,Right);
if(Left==Right) {
tree[index].val=a[Left];
return index;
}
int mid=(Left+Right)>>1;
ls=build(Left,mid,a);
rs=build(mid+1,Right,a);
push_up(index);
return index;
}
void push_up(int index) {
tree[index].val=__gcd(tree[ls].val,tree[rs].val);
}
void modify(int index,int target,LL val) {
if(target>tree[index].right||target<tree[index].left)return;
if(tree[index].left==tree[index].right) {
tree[index].val+=val;
return;
}
modify(ls,target,val);
modify(rs,target,val);
push_up(index);
}
LL query(int index,int Left,int Right) {
if(Left>tree[index].right||Right<tree[index].left)return 0;
if(Left<=tree[index].left&&Right>=tree[index].right)return tree[index].val;
return __gcd(query(ls,Left,Right),query(rs,Left,Right));
}
int merge(int x,int y) {
int index=++size;
tree[index]=tree[x];
if(tree[index].left==tree[index].right) {
tree[index].val=__gcd(tree[x].val,tree[y].val);
return index;
}
ls=merge(tree[x].lson,tree[y].lson);
rs=merge(tree[x].rson,tree[y].rson);
push_up(index);
return index;
}
} stin;

#undef ls
#undef rs

int n,m,x,y,q;
vector<LL> a[maxn];

struct Segment_Tree_out {
struct Tree {
int left,right,root;
Tree(int l=0,int r=0,int x=0):left(l),right(r),root(x) {}
} tree[maxn<<2];
#define ls index<<1
#define rs index<<1|1
void build(int index,int Left,int Right,vector<LL>* a) {
tree[index]=Tree(Left,Right);
if(Left==Right) {
tree[index].root=stin.build(1,m,a[Left]);
return;
}
int mid=(Left+Right)>>1;
build(ls,Left,mid,a);
build(rs,mid+1,Right,a);
tree[index].root=stin.merge(tree[ls].root,tree[rs].root);
}
void push_up(int index,int target) {
LL l=stin.query(tree[ls].root,target,target),r=stin.query(tree[rs].root,target,target),last=stin.query(tree[index].root,target,target);
stin.modify(tree[index].root,target,__gcd(l,r)-last);
}
void modify(int index,int xtarget,int ytarget,LL val) {
if(xtarget>tree[index].right||xtarget<tree[index].left)return;
if(tree[index].left==tree[index].right) {
stin.modify(tree[index].root,ytarget,val);
return;
}
modify(ls,xtarget,ytarget,val);
modify(rs,xtarget,ytarget,val);
push_up(index,ytarget);
}
LL query(int index,int xl,int xr,int yl,int yr) {
if(xl>tree[index].right||xr<tree[index].left)return 0;
if(xl<=tree[index].left&&xr>=tree[index].right)return stin.query(tree[index].root,yl,yr);
return __gcd(query(ls,xl,xr,yl,yr),query(rs,xl,xr,yl,yr));
}
} st;

int main() {
n=Get_Int();
m=Get_Int();
x=Get_Int();
y=Get_Int();
q=Get_Int();
for(int i=1; i<=n; i++) {
a[i].push_back(0);
for(int j=1; j<=m; j++)
a[i].push_back(Get_Int());
}
for(int i=1; i<=n; i++) { //横向差分
for(int j=1; j<y; j++)a[i][j]-=a[i][j+1];
for(int j=m; j>y; j--)a[i][j]-=a[i][j-1];
}
for(int j=1; j<=m; j++) { //纵向差分
for(int i=1; i<x; i++)a[i][j]-=a[i+1][j];
for(int i=n; i>x; i--)a[i][j]-=a[i-1][j];
}
st.build(1,1,n,a);
for(int i=1; i<=q; i++) {
int opt=Get_Int();
if(opt==0) {
int x1=x-Get_Int(),y1=y-Get_Int(),x2=x+Get_Int(),y2=y+Get_Int();
LL ans=st.query(1,x1,x2,y1,y2);
printf("%lld\n",abs(ans));
} else {
int x1=Get_Int(),y1=Get_Int(),x2=Get_Int(),y2=Get_Int();
LL val=Get_Int();
//左上(x1,y1)
if(x1<=x&&y1<=y&&x1-1>=1&&y1-1>=1)st.modify(1,x1-1,y1-1,val);
else if(x1<=x&&y1>y&&x1-1>=1)st.modify(1,x1-1,y1,-val);
else if(x1>x&&y1<=y&&y1-1>=1)st.modify(1,x1,y1-1,-val);
else if(x1>x&&y1>y)st.modify(1,x1,y1,val);
//右上(x1,y2)
if(x1<=x&&y2>=y&&x1-1>=1&&y2+1<=m)st.modify(1,x1-1,y2+1,val);
else if(x1<=x&&y2<y&&x1-1>=1)st.modify(1,x1-1,y2,-val);
else if(x1>x&&y2>=y&&y2+1<=m)st.modify(1,x1,y2+1,-val);
else if(x1>x&&y2<y)st.modify(1,x1,y2,val);
//左下(x2,y1)
if(x2>=x&&y1<=y&&x2+1<=n&&y1-1>=1)st.modify(1,x2+1,y1-1,val);
else if(x2<x&&y1<=y&&y1-1>=1)st.modify(1,x2,y1-1,-val);
else if(x2>=x&&y1>y&&x2+1<=n)st.modify(1,x2+1,y1,-val);
else if(x2<x&&y1>y)st.modify(1,x2,y1,val);
//右下(x2,y2)
if(x2>=x&&y2>=y&&x2+1<=n&&y2+1<=m)st.modify(1,x2+1,y2+1,val);
else if(x2<x&&y2>=y&&y2+1<=m)st.modify(1,x2,y2+1,-val);
else if(x2>=x&&y2<y&&x2+1<=n)st.modify(1,x2+1,y2,-val);
else if(x2<x&&y2<y)st.modify(1,x2,y2,val);
//过横分割线
if(x1<=x&&x2>=x) {
//左端点(x,y1)
if(y1<=y&&y1-1>=1)st.modify(1,x,y1-1,-val);
else if(y1>y)st.modify(1,x,y1,val);
//右端点(x,y2)
if(y2>=y&&y2+1<=m)st.modify(1,x,y2+1,-val);
else if(y2<y)st.modify(1,x,y2,val);
}
//过竖分割线
if(y1<=y&&y2>=y) {
//上端点(x1,y)
if(x1<=x&&x1-1>=1)st.modify(1,x1-1,y,-val);
else if(x1>x)st.modify(1,x1,y,val);
//下端点(x2,y)
if(x2>=x&&x2+1<=n)st.modify(1,x2+1,y,-val);
else if(x2<x)st.modify(1,x2,y,val);
}
//过点(x,y)
if(x1<=x&&x2>=x&&y1<=y&&y2>=y)st.modify(1,x,y,val);
}
}
return 0;
}
姥爷们赏瓶冰阔落吧~