单点更新
void update(int x,int y,int n){
for(int i=x;i<=n;i+=lowbit(i)) //x为更新的位置,y为加的数,n为数组最大值
c[i] += y;
}
区间查询(1 - x)
int getsum(int x){
int ans = 0;
for(int i=x;i;i-=lowbit(i))
ans += c[i];
return ans;
}
高级操作
求逆序对
对于数组a,我们将其离散化处理为b[].区间查询与单点修改代码如下
int lowbit(int x) {
return x & (-x);
}
void update(int p) {
while (p <= n) {
c[p] ++;
p += lowbit(p);
}
}
int getsum(int p) {
int res = 0;
while(p) {
res += c[p];
p -= lowbit(p);
}
return res;
}
a的逆序对个数为:
for(int i = 1; i <= n; i++) {
update(b[i]);
res += (i - getsum(b[i]));
}
poj 2299
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<list>
#include<math.h>
#include<vector>
#include<stack>
#include<string>
#include<cstring>
#include<string.h>
using namespace std;
typedef long long LL;
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
const int MAXN = 5e5 + 10;
const double eps = 1e-8;
int c[MAXN];
int n;
int a[MAXN],b[MAXN];
int lowbit(int x) {
return x & (-x);
}
void update(int p) {
while (p <= n) {
c[p] ++;
p += lowbit(p);
}
}
int getsum(int p) {
int res = 0;
while(p) {
res += c[p];
p -= lowbit(p);
}
return res;
}
int main()
{
while (~scanf("%d", &n) && n) {
memset(c,0,sizeof c);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
b[i] = a[i];
}
sort(a + 1, a + 1 + n);
int cnt = unique(a + 1, a + 1 + n) - a - 1;
for (int i = 1; i <= n; i++)
b[i] = lower_bound(a + 1, a + 1 + cnt, b[i]) - a;
LL res = 0;
for(int i = 1; i <= n; i++) {
update(b[i]);
res += (i - getsum(b[i]));
}
printf("%lld\n",res);
}
}
res就是逆序对个数,ask,需注意b[i]应该大于0
求区间最大值
void Update(int i,int v)
{
while(i<=maxY)
{
t[i] = max(t[i],v);
i += lowbit(i);
}
}
int query(int i)
{
int ans = 0;
while(i)
{
ans = max(ans,t[i]);
i -= lowbit(i);
}
return ans;
}

int lowbit(int x) {
return x & -x;
}
void add(int p,int x) { //这个函数用来在树状数组中直接修改
while(p <= n) {
c[p] += x;
p += lowbit(p);
}
}
void range_add(int l,int r,int x) { //给区间[l, r]加上x
add(l,x);
add(r + 1, -x);
}
int ask(int p) { //单点查询前缀和
int res = 0;
while(p) {
res += c[p];
p -= lowbit(p);
}
return res;
}

void add(ll p, ll x){
for(int i = p; i <= n; i += i & -i)
sum1[i] += x, sum2[i] += x * p;
}
void range_add(ll l, ll r, ll x){
add(l, x), add(r + 1, -x);
}
ll ask(ll p){
ll res = 0;
for(int i = p; i; i -= i & -i)
res += (p + 1) * sum1[i] - sum2[i];
return res;
}
ll range_ask(ll l, ll r){
return ask(r) - ask(l - 1);
}
用这个做区间修改区间求和的题,无论是时间上还是空间上都比带lazy标记的线段树要优。

void add(int x, int y, int z){ //将点(x, y)加上z
int memo_y = y;
while(x <= n){
y = memo_y;
while(y <= n)
tree[x][y] += z, y += y & -y;
x += x & -x;
}
}
int ask(int x, int y){//求左上角为(1,1)右下角为(x,y) 的矩阵和
int res = 0, memo_y = y;
while(x){
y = memo_y;
while(y)
res += tree[x][y], y -= y & -y;
x -= x & -x;
}
return res;
}

void add(int x, int y, int z){
int memo_y = y;
while(x <= n){
y = memo_y;
while(y <= n)
tree[x][y] += z, y += y & -y;
x += x & -x;
}
}
void range_add(int xa, int ya, int xb, int yb, int z){
add(xa, ya, z);
add(xa, yb + 1, -z);
add(xb + 1, ya, -z);
add(xb + 1, yb + 1, z);
}
int ask(int x, int y){
int res = 0, memo_y = y;
while(x){
y = memo_y;
while(y)
res += tree[x][y], y -= y & -y;
x -= x & -x;
}
return res;
}

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
ll read(){
char c; bool op = 0;
while((c = getchar()) < '0' || c > '9')
if(c == '-') op = 1;
ll res = c - '0';
while((c = getchar()) >= '0' && c <= '9')
res = res * 10 + c - '0';
return op ? -res : res;
}
const int N = 205;
ll n, m, Q;
ll t1[N][N], t2[N][N], t3[N][N], t4[N][N];
void add(ll x, ll y, ll z){
for(int X = x; X <= n; X += X & -X)
for(int Y = y; Y <= m; Y += Y & -Y){
t1[X][Y] += z;
t2[X][Y] += z * x;
t3[X][Y] += z * y;
t4[X][Y] += z * x * y;
}
}
void range_add(ll xa, ll ya, ll xb, ll yb, ll z){ //(xa, ya) 到 (xb, yb) 的矩形
add(xa, ya, z);
add(xa, yb + 1, -z);
add(xb + 1, ya, -z);
add(xb + 1, yb + 1, z);
}
ll ask(ll x, ll y){
ll res = 0;
for(int i = x; i; i -= i & -i)
for(int j = y; j; j -= j & -j)
res += (x + 1) * (y + 1) * t1[i][j]
- (y + 1) * t2[i][j]
- (x + 1) * t3[i][j]
+ t4[i][j];
return res;
}
ll range_ask(ll xa, ll ya, ll xb, ll yb){
return ask(xb, yb) - ask(xb, ya - 1) - ask(xa - 1, yb) + ask(xa - 1, ya - 1);
}
int main(){
n = read(), m = read(), Q = read();
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
ll z = read();
range_add(i, j, i, j, z);
}
}
while(Q--){
ll ya = read(), xa = read(), yb = read(), xb = read(), z = read(), a = read();
if(range_ask(xa, ya, xb, yb) < z * (xb - xa + 1) * (yb - ya + 1))
range_add(xa, ya, xb, yb, a);
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++)
printf("%lld ", range_ask(i, j, i, j));
putchar('\n');
}
return 0;
}