Problem F
发布时间: 2017年6月28日 10:31 最后更新: 2017年6月29日 21:35 时间限制: 2000ms 内存限制: 64M
给定一个 n×m 的矩形, 初始时所有元素都为 0
给出 q 个操作, 操作有三种
对于形如 1 x 的操作, 将第 x 行的所有元素异或 1
对于形如 2 y 的操作, 将第 y 列的所有元素异或 1
对于形如
3
x1
y1
x2
y2
的操作, 输出
(x1,y1)
-
(x2,y2)
这段矩形区域内
1
的个数
9×105≤n≤106 , 9×105≤m≤106 , 9×105≤q≤106
第一行三个整数
n
,
m
,
q
, 意义如上所述。
接下来
q
行, 每行第一个数为
opt
, 如果
opt=1
或
opt=2
, 后面紧跟一个数, 意义如上所述; 如果
opt=3
, 后面紧跟四个数, 意义如上所述。
对于每个操作 3 , 输出答案, 一行一个。
4 4 5 3 1 1 4 4 1 4 3 1 1 4 4 2 4 3 1 1 4 4
0 4 6
大水题一道,我们知道,异或的特性如果有1个数,他本身进行偶数次异或那么就是0;
这道题我们这样想,对于一行来说,异或奇数次是一样的,异或偶数次也是一样的。
那么这个问题就可以简化,我们按行建一个树状数组,里面保存有多少行的 异或次数为奇数次。
我们再按照列建一个树状数组,里面保存有多少列的异或次数为奇数次。
那么要求矩阵x1,x2,y1,y2里的1的个数,1的个数就等于(row[x2]-row[x1-1])*(y2-y1+1) + (col[y2] - col[y1-1])*(x2-x1+1) - 2*(row[x2]-row[x1-1])*(row[x2]-row[x1-1])
其中row[i]与col[i]都可以log(n)时间内用树状数组求出来
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MAX = 1e6+7;
int row[MAX];
int mark_row[MAX];
int mark_col[MAX];
int col[MAX];
int n,m,q;
inline int lowbit(int x){
return x & (-x);
}
void add(int in[],int pos,int val){
while(pos <= MAX){
in[pos] += val;
pos += lowbit(pos);
}
}
int getsum(int in[],int pos){
int res = 0;
while(pos){
res += in[pos];
pos -= lowbit(pos);
}
return res;
}
int main(){
scanf("%d%d%d",&n,&m,&q);
while(q--){
int opt;scanf("%d",&opt);
if(opt == 1){
int x;scanf("%d",&x);
if(mark_row[x]){
add(row,x,-1);
mark_row[x] = 0;
}
else{
add(row,x,1);
mark_row[x] = 1;
}
}
else if(opt == 2){
int x;scanf("%d",&x);
if(mark_col[x]){
add(col,x,-1);
mark_col[x] = 0;
}
else{
add(col,x,1);
mark_col[x] = 1;
}
}
else{
int x1,x2,y1,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int ans1 = getsum(row,x2) - getsum(row,x1-1);
int ans2 = getsum(col,y2) - getsum(col,y1-1);
int ans = ans1*(y2-y1+1) + ans2*(x2-x1+1) - 2*ans1*ans2;
printf("%d\n",ans);
}
}
return 0;
}