• LOJ #135. 二维树状数组 3:区间修改,区间查询 题解


    CSDN同步

    原题链接

    前置知识:

    一维树状数组的区间修改与区间查询。

    简要题意:

    维护二维数组的矩阵加与矩阵查。

    很显然,如果你用 二维线段树 的话,常数较大,加上要开 ( ext{long long}),很可能会 ( ext{MLE + TLE}) 的双倍快乐。

    所以我们要用 二维树状数组 解决这道题目。

    考虑常规前缀和,二维的前缀和需要维护 (4) 个节点,我们也需要一一维护。

    也就是我们要维护 (4) 个差分数组用来一一对应矩阵的四个角,并用 滚一维 的方式,把二维的更新。注意区间加和的细节。

    时间复杂度:(mathcal{O}(n^2 log^2 n) - mathcal{O}(log^2 n)).

    实际得分:(100pts).

    双倍经验:P4514 上帝造题的七分钟,不过这道题目需要大力卡常(本人卡了半天还是 (81),自闭了,( ext{LOJ}) 评测器最快!)

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize(5000)
    #pragma GCC optimize(1000000000)
    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #pragma GCC optimize("-fgcse")
    #pragma GCC optimize("-fgcse-lm")
    #pragma GCC optimize("-fipa-sra")
    #pragma GCC optimize("-ftree-pre")
    #pragma GCC optimize("-ftree-vrp")
    #pragma GCC optimize("-fpeephole2")
    #pragma GCC optimize("-ffast-math")
    #pragma GCC optimize("-fsched-spec")
    #pragma GCC optimize("unroll-loops")
    #pragma GCC optimize("-falign-jumps")
    #pragma GCC optimize("-falign-loops")
    #pragma GCC optimize("-falign-labels")
    #pragma GCC optimize("-fdevirtualize")
    #pragma GCC optimize("-fcaller-saves")
    #pragma GCC optimize("-fcrossjumping")
    #pragma GCC optimize("-fthread-jumps")
    #pragma GCC optimize("-funroll-loops")
    #pragma GCC optimize("-fwhole-program")
    #pragma GCC optimize("-freorder-blocks")
    #pragma GCC optimize("-fschedule-insns")
    #pragma GCC optimize("inline-functions")
    #pragma GCC optimize("-ftree-tail-merge")
    #pragma GCC optimize("-fschedule-insns2")
    #pragma GCC optimize("-fstrict-aliasing")
    #pragma GCC optimize("-fstrict-overflow")
    #pragma GCC optimize("-falign-functions")
    #pragma GCC optimize("-fcse-skip-blocks")
    #pragma GCC optimize("-fcse-follow-jumps")
    #pragma GCC optimize("-fsched-interblock")
    #pragma GCC optimize("-fpartial-inlining")
    #pragma GCC optimize("no-stack-protector")
    #pragma GCC optimize("-freorder-functions")
    #pragma GCC optimize("-findirect-inlining")
    #pragma GCC optimize("-fhoist-adjacent-loads")
    #pragma GCC optimize("-frerun-cse-after-loop")
    #pragma GCC optimize("inline-small-functions")
    #pragma GCC optimize("-finline-small-functions")
    #pragma GCC optimize("-ftree-switch-conversion")
    #pragma GCC optimize("-foptimize-sibling-calls")
    #pragma GCC optimize("-fexpensive-optimizations")
    #pragma GCC optimize("-funsafe-loop-optimizations")
    #pragma GCC optimize("inline-functions-called-once")
    #pragma GCC optimize("-fdelete-null-pointer-checks")
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=(1<<12)+1;
    #define int long long
    
    inline int read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
    
    inline void write(int x) {
    	if(x<0) {putchar('-');write(-x);return;}
    	if(x<10) {putchar(char(x%10+'0'));return;}
    	write(x/10);putchar(char(x%10+'0'));
    }
    
    int n,m;
    struct BIT {
    	int a[N][N];
    	inline void add(int x,int y,int t) {
    		for(register int i=x;i<=n;i+=(i&-i))
    		for(register int j=y;j<=m;j+=(j&-j)) a[i][j]+=t;
    	} //加
    
    	inline int query(int x,int y) {
    		int t=0;
    		for(register int i=x;i>=1;i-=(i&-i))
    		for(register int j=y;j>=1;j-=(j&-j)) t+=a[i][j];
    		return t;
    	} //询问
    }A,B,C,D; //四个树状数组
    
    inline int calc(int x,int y) {
    	return A.query(x,y)*(x*y+x+y+1)-B.query(x,y)*(y+1)
    		-C.query(x,y)*(x+1)+D.query(x,y);
    } //计算二维前缀和的答案
    
    inline void Add(int x,int y,int t) {
    	A.add(x,y,t); B.add(x,y,t*x);
    	C.add(x,y,t*y); D.add(x,y,t*x*y);
    } //修改四个节点
    
    signed main() {
    	n=read(),m=read(); int op;
    	while(cin>>op) {
    		int x1=read(),y1=read(),x2,y2,t;
    		if(op==1) {
    			x2=read(),y2=read(); t=read(); Add(x1,y1,t); Add(x1,y2+1,-t);
    			Add(x2+1,y1,-t); Add(x2+1,y2+1,t);
    		} else x2=x1,y2=y1,write(calc(x2,y2)-calc(x1-1,y2)-calc(x2,y1-1)+calc(x1-1,y1-1)),
    		putchar('
    ');
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    CISP/CISA 每日一题 七
    CISP/CISA 每日一题 六
    CISP/CISA 每日一题 五
    C++编码优化之减少冗余拷贝或赋值
    CISP/CISA 每日一题 四
    CISP/CISA 每日一题 三
    CISP/CISA 每日一题 二
    CISP/CISA 每日一题
    C#与C++ DLL的交互
    数据同步工具otter(二)
  • 原文地址:https://www.cnblogs.com/bifanwen/p/13199953.html
Copyright © 2020-2023  润新知