【模板篇】树状数组(五)
来源:互联网 发布:软件版权声明格式 编辑:程序博客网 时间:2024/06/03 20:53
好的 我们之前说过了树状数组的
单点加区间查
区间加单点查
区间加区间查
和没什么用的单点改查区间最值
我们发现,这都是一维的树状数组,只能用来处理一维的东西..
我们就想,为什么不能把树状数组放到平面上呢?
然后就出现了二维树状数组
大概就是长这个样子(大雾)
int c[N][M];
(如果要画出他表示的样子大概要一个3D立体图,可是这个地方太小,写不下= =)
既然是树状数组,我们就不能忘记lowbit小朋友= =
他现在长这个样子
x&-x;
(其实并没有什么改动)
我们在二维中的单点指的就是坐标(x,y),区间指的就是以(x1,y1)为左上角(x2,y2)为右下角的矩形= =
我们已经知道,树状数组维护的是前缀和,所以二维树状数组中每个点查到的就是以(1,1)为左上角,这个点为右下角的矩形的区间和= =
所以我们单点加区间查可以这么写:
void add(int x,int y,int s) for(int i=x;i<=n;i+=lowbit(i)) for(int j=y;j<=m;j+=lowbit(j)) //其实就是多了一重循环 c[i][j]+=s;int query(int x,int y){ int s=0; for(int i=x;i;i-=lowbit(i)) for(int j=y;j<=m;j+=lowbit(j)) s+=c[i][j]; return s;}//根据二维前缀和的性质,区间查是这样的int _query(int x1,int y1,int x2,int y2){ return query(x2,y2)-(query,x1-1,y2)-query(x2,y1-1)+query(x1-1,y2-1);}
*唯一要说明的是,循环不能再像一维的一样写
for(;x;-=lowbit(x)) for(;y;y-=lowbit(y)) ...
因为x跑之后几遍的时候,y是不应该被修改的..然后就会出现玄学的错误= =
区间加单点查可以这么写:
void add(int x,int y,int s) for(int i=x;i<=n;i+=lowbit(i)) for(int j=y;j<=m;j+=lowbit(j)) c[i][j]+=s;int query(int x,int y){ int s=0; for(int i=x;i;i-=lowbit(i)) for(int j=y;j<=m;j+=lowbit(j)) s+=c[i][j]; return s;}//二维差分void _add(int x1,int x2,int y1,int y2,int s){ add(x1,y1,s); add(x1,y2+1,-s); add(x2+1,y1,-s); add(x2+1,y2+1,s);}
先这样吧= =
对于区间加单点查,贴一道例题(其实是因为做了这道题我才想到继续更树状数组的= =)
这个昨天的CodeForces上的一道比D题水多了的E题= =
http://codeforces.com/problemset/problem/869/E
本来自己的思路是对的,结果自己觉得不行就没有写,后来发现是自己nc…(我还是太菜了QAQ) (虽然真正让我自己写还是会WA因为并没有意识到矩阵的编号会被卡OvO)
其实这题完全是可做的(虽然最后因为map的问题交了n遍才过= =)
题目大意(英文题,伤不起):
给一个
1. 在以(x1,y1)为左上角,(x2,y2)为右下角的矩形外侧建一堵墙..(不会盖到空地的最外围)
2. 拆除以(x1,y1)为左上角,(x2,y2)为右下角的矩形外侧的墙..(墙保证存在)
3. 查询(x1,y1)格与(x2,y2)格是否连通= =
其中,墙围保证没有公共点..
其实就是给每个矩阵编个号,1操作就把区间加这个编号,2操作就把这个区间减这个编号,3操作就查询这两个点的编号是否相等即可= =
对于每堵墙的编号,我们开个map存一下即可..
#include <map>#include <cstdio>#include <cstdlib>using namespace std;#define mp make_pairtypedef long long ll;typedef pair<int,int> zb;map<pair<zb,zb>,int> mmp;inline int lb(int x){return x&-x;}inline ll myrand(){return (ll)rand()<<15|rand();}int n,m,q;ll c[2505][2505];inline int gn(){ int a=0;char c=getchar();for(;c<'0'||c>'9';c=getchar()); for(;c>='0'&&c<='9';c=getchar())a=(a<<1)+(a<<3)+c-'0';return a;}void _add(int x,int y,ll s){ for(int i=x;i<=n;i+=lb(i)) for(int j=y;j<=m;j+=lb(j)) c[i][j]+=s;}ll query(int x,int y){ ll s=0; for(int i=x;i;i-=lb(i)) for(int j=y;j;j-=lb(j)) s+=c[i][j]; return s;}void add(int x1,int y1,int x2,int y2,ll s){ _add(x1,y1,s); _add(x1,y2+1,-s); _add(x2+1,y1,-s); _add(x2+1,y2+1,s);}int main(){ srand(0x1204); //这个地方的种子大约是没有什么太大问题的.. n=gn();m=gn();q=gn(); while(q--){ int opt=gn(),x1=gn(),y1=gn(),x2=gn(),y2=gn(); switch(opt){ case 1:{ ll k=myrand(); //这个地方不能简单的insert,因为可能会出现拆了又盖 盖了又拆的情况,如果不erase, //后面的insert就会沦为无效操作= = 就会在第36个点WA... mmp[mp(mp(x1,y1),mp(x2,y2))]=k;// mmp.insert(mp(mp(mp(x1,y1),mp(x2,y2)),k));// add(x1,y1,x2,y2,k); break; } case 2:{ //如果上面选择了insert那么这里就要erase掉// pair<zb,zb> pr=mp(mp(x1,y1),mp(x2,y2));// int k=mmp[pr];// mmp.erase(pr); int k=mmp[mp(mp(x1,y1),mp(x2,y2))]; add(x1,y1,x2,y2,-k); break; } default:{ ll q1=query(x1,y1),q2=query(x2,y2); if(q1==q2) puts("Yes"); else puts("No"); break; } } }}
哒哒哒~~
- 【模板篇】树状数组(五)
- 树状数组(模板)
- 树状数组 (模板)
- 树状数组(模板)
- (树状数组)模板
- 树状数组(模板)
- 树状数组 (模板)
- 【模板篇】树状数组们(一)
- 【模板篇】树状数组们(二)
- 【模板篇】树状数组们(三)
- 【模板篇】树状数组们(四)
- 树状数组(模板+原理)
- 无题(树状数组模板)
- 初识树状数组(模板)
- 【模板】树状数组(详解)
- 树状数组模板+poj1195(二维树状数组)
- hdu4000(一维树状数组模板)
- hdu 1892(二维树状数组模板)
- http协议
- hdu4578
- 定义函数-学习笔记
- Qt实现正弦曲线图(类似示波器功能)
- javascript中的浅复制与深复制
- 【模板篇】树状数组(五)
- mdadm命令详解及实验过程
- 线性结构之单链表
- 排列问题
- JavaScript获取java变量值
- oracle多表查询
- 字典树 总结
- 20171007-Java入门笔记(一)this、覆写、equals、==
- HTML技术短暂的学习总结