本题的主要算法就是区间更新和区间求和;
可以用线段树和树状数组来做;
感觉线段树写的太麻烦了,看到官方题解上说可以用树状数组做,觉得很神奇,以前用过的树状数组都是单点维护,区间求和的;
其实树状数组还可以区间维护,单点求值;和区间维护,区间求和的;
详情请见博客。
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #define maxn 4000010 #define ll long long using namespace std; ll a[2][maxn]; ll b[2][maxn]; void add_a(int flag,int x,ll value) { while(x>0) { a[flag][x]+=value; x-=x&(-x); } } void add_b(int flag,int n,int x,ll value) { for(int i=x;i<=n;i+=i&(-i)) b[flag][i]+=x*value; } ll sum_a(int flag,int n,int x) { ll sum=0; while(x<=n) { sum+=a[flag][x]; x+=x&(-x); } return sum; } ll sum_b(int flag,int x) { ll sum=0; while(x>0) { sum+=b[flag][x]; x-=x&(-x); } return sum; } ll getsum(int flag,int n,int x) { if(x) return sum_a(flag,n,x)*x+sum_b(flag,x-1); else { return 0; } } int main() { int n,m,w; int comand; int x1,x2,y1,y2; int v; scanf("%d%d%d",&n,&m,&w); for(int i=0; i<w; i++) { scanf("%d",&comand); if(comand==0) { scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&v); ll vy=v*(y2-y1+1); ll vx=v*(x2-x1+1); add_a(0,x2,vy); add_b(0,n,x2,vy); if(x1>1) { add_a(0,x1-1,-vy); add_b(0,n,x1-1,-vy); } add_a(1,y2,vx); add_b(1,m,y2,vx); if(y1>1) { add_a(1,y1-1,-vx); add_b(1,m,y1-1,-vx); } } else { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); ll tmp1=getsum(0,n,x2)-getsum(0,n,x1-1); ll tmp2=getsum(1,m,y1-1); ll tmp3=getsum(1,m,m)-getsum(1,m,y2); cout<<tmp1-tmp2-tmp3<<endl; } } return 0; }