浅谈树状数组与主席树:https://www.cnblogs.com/AKMer/p/9946944.html

题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=2877

这就是个屎题。

而且至今我还不知道为什么洛谷和本地都可以过但是\(BZOJ\)会\(RE\)

利用更相减损数以棋盘守护者为中心进行二维差分,那么每次修改就变成若干个点的值的修改了。

然后二维线段树维护差分值。

详细一点你们可以看这个博客(我是懒得搞了):http://www.cnblogs.com/milky-w/p/8530723.html

反正我是不想再来回头看这题了,简直屎得一批。

2019.01.03更新:递归版代码开O3可以在BZOJ过,所以我觉得是递归的锅,果然把所有递归全部改成非递归就可以过了。还是清楚为什么递归层数并不多会RE。

时间复杂度:\(O(nmlognlogm)\)

空间复杂度:\(O(mn)\)

非递归版代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll; const int maxn=5e5+5; int n,m,X,Y,T;
ll a[maxn],b[maxn]; ll read() {
ll x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} ll gcd(ll a,ll b) {
while(b) {
ll tmp=b;b=a%b;
a=tmp;
}
return abs(a);
} struct tree_node {
int p,l,r; tree_node () {} tree_node (int _p,int _l,int _r) {
p=_p,l=_l,r=_r;
}
}; struct segment_tree_y {
int tot,top;
tree_node sta[maxn<<1];
int ls[maxn<<2],rs[maxn<<2];
ll val[maxn<<2],ans[maxn<<2];
int rt1[maxn<<1],rt2[maxn<<1]; void build(int root,int x) {
sta[++top]=tree_node(root,1,m);
int now=1;
while(now<=top) {
if(sta[now].l==sta[now].r) {now++;continue;}
int mid=(sta[now].l+sta[now].r)>>1;
ls[sta[now].p]=++tot,rs[sta[now].p]=++tot;
sta[++top]=tree_node(ls[sta[now].p],sta[now].l,mid);
sta[++top]=tree_node(rs[sta[now].p],mid+1,sta[now].r);
now++;
}
while(top) {
tree_node tmp=sta[top--];
if(tmp.l==tmp.r)val[tmp.p]=a[(x-1)*m+tmp.l];
else val[tmp.p]=gcd(val[ls[tmp.p]],val[rs[tmp.p]]);
}
} void update(int root,int root1,int root2) {
sta[++top]=tree_node(root,1,m);
rt1[top]=root1,rt2[top]=root2;
int now=1;
while(now<=top) {
if(sta[now].l==sta[now].r) {now++;continue;}
int mid=(sta[now].l+sta[now].r)>>1;
ls[sta[now].p]=++tot,rs[sta[now].p]=++tot;
sta[++top]=tree_node(ls[sta[now].p],sta[now].l,mid);
rt1[top]=ls[rt1[now]],rt2[top]=ls[rt2[now]];
sta[++top]=tree_node(rs[sta[now].p],mid+1,sta[now].r);
rt1[top]=rs[rt1[now]],rt2[top]=rs[rt2[now]];
now++;
}
while(top) {
tree_node tmp=sta[top];
int u=rt1[top],v=rt2[top];top--;
if(tmp.l==tmp.r)val[tmp.p]=gcd(val[u],val[v]);
else val[tmp.p]=gcd(val[ls[tmp.p]],val[rs[tmp.p]]);
}
} ll query(int rt,int L,int R) {
sta[++top]=tree_node(rt,1,m);
int now=1;
while(now<=top) {
if(L<=sta[now].l&&sta[now].r<=R) {now++;continue;}
int mid=(sta[now].l+sta[now].r)>>1;
if(L<=mid)sta[++top]=tree_node(ls[sta[now].p],sta[now].l,mid);
if(R>mid)sta[++top]=tree_node(rs[sta[now].p],mid+1,sta[now].r);
now++;
}
while(top) {
tree_node tmp=sta[top--];
if(L<=tmp.l&&tmp.r<=R)ans[tmp.p]=val[tmp.p];
else {
ans[tmp.p]=0;
int mid=(tmp.l+tmp.r)>>1;
if(L<=mid)ans[tmp.p]=ans[ls[tmp.p]];
if(R>mid)ans[tmp.p]=gcd(ans[tmp.p],ans[rs[tmp.p]]);
}
}
return ans[rt];
} void change(int p,int pos,ll v,bool opt) {
sta[++top]=tree_node(p,1,m);
int now=1;
while(now<=top) {
if(sta[now].l==sta[now].r) {now++;continue;}
int mid=(sta[now].l+sta[now].r)>>1;
if(pos<=mid)sta[++top]=tree_node(ls[sta[now].p],sta[now].l,mid);
else sta[++top]=tree_node(rs[sta[now].p],mid+1,sta[now].r);
now++;
}
while(top) {
tree_node tmp=sta[top--];
if(tmp.l==tmp.r) {
if(opt)val[tmp.p]+=v;
else val[tmp.p]=v;
}
else val[tmp.p]=gcd(val[ls[tmp.p]],val[rs[tmp.p]]);
}
}
}T2; struct segment_tree_x {
int top;
int rt[maxn<<2];
ll ans[maxn<<2];
tree_node sta[maxn<<1]; void build() {
sta[++top]=tree_node(1,1,n);
int now=1;
while(now<=top) {
if(sta[now].l==sta[now].r) {now++;continue;}
int mid=(sta[now].l+sta[now].r)>>1;
sta[++top]=tree_node(sta[now].p<<1,sta[now].l,mid);
sta[++top]=tree_node(sta[now].p<<1|1,mid+1,sta[now].r);
now++;
}
while(top) {
tree_node tmp=sta[top--];rt[tmp.p]=++T2.tot;
if(tmp.l==tmp.r)T2.build(rt[tmp.p],tmp.l);
else T2.update(rt[tmp.p],rt[tmp.p<<1],rt[tmp.p<<1|1]);
}
} ll query(int x1,int x2,int y1,int y2) {
sta[++top]=tree_node(1,1,n);
int now=1;
while(now<=top) {
if(x1<=sta[now].l&&sta[now].r<=x2) {now++;continue;}
int mid=(sta[now].l+sta[now].r)>>1;
if(x1<=mid)sta[++top]=tree_node(sta[now].p<<1,sta[now].l,mid);
if(x2>mid)sta[++top]=tree_node(sta[now].p<<1|1,mid+1,sta[now].r);
now++;
}
while(top) {
tree_node tmp=sta[top--];
if(x1<=tmp.l&&tmp.r<=x2)ans[tmp.p]=T2.query(rt[tmp.p],y1,y2);
else {
ans[tmp.p]=0;int mid=(tmp.l+tmp.r)>>1;
if(x1<=mid)ans[tmp.p]=ans[tmp.p<<1];
if(x2>mid)ans[tmp.p]=gcd(ans[tmp.p],ans[tmp.p<<1|1]);
}
}
return ans[1];
} void add(int x,int y,ll v) {
if(x<1||x>n||y<1||y>m)return;
sta[++top]=tree_node(1,1,n);
int now=1;
while(now<=top) {
if(sta[now].l==sta[now].r) {now++;continue;}
int mid=(sta[now].l+sta[now].r)>>1;
if(x<=mid)sta[++top]=tree_node(sta[now].p<<1,sta[now].l,mid);
else sta[++top]=tree_node(sta[now].p<<1|1,mid+1,sta[now].r);
now++;
}
while(top) {
tree_node tmp=sta[top--];
if(tmp.l==tmp.r)T2.change(rt[tmp.p],y,v,1);
else {
ll lv=T2.query(rt[tmp.p<<1],y,y);
ll rv=T2.query(rt[tmp.p<<1|1],y,y);
T2.change(rt[tmp.p],y,gcd(lv,rv),0);
}
}
}
}T1; int main() {
n=read(),m=read(),X=read(),Y=read(),T=read();
for(int i=1;i<=n*m;i++)a[i]=read();
for(int i=1;i<=n*m;i++) {
int pos=(i-1)%m+1;
if(pos<Y)b[i]=a[i]-a[i+1];
else if(pos>Y)b[i]=a[i]-a[i-1];
else b[i]=a[i];
}
for(int i=1;i<=n*m;i++) {
int pos=(i-1)/m+1;
if(pos<X)a[i]=b[i]-b[i+m];
else if(pos>X)a[i]=b[i]-b[i-m];
else a[i]=b[i];
}
T1.build();
while(T--) {
int opt=read(),x1=read(),y1=read(),x2=read(),y2=read();
if(!opt) {
x1=X-x1,x2=X+x2,y1=Y-y1,y2=Y+y2;
printf("%lld\n",T1.query(x1,x2,y1,y2));
}
if(opt) {
ll val=read();
if(x1<=X&&x2>=X&&y1<=Y&&y2>=Y) {
T1.add(X,Y,val);
T1.add(x1-1,y1-1,val);
T1.add(x1-1,y2+1,val);
T1.add(x2+1,y1-1,val);
T1.add(x2+1,y2+1,val);
T1.add(x1-1,Y,-val);
T1.add(x2+1,Y,-val);
T1.add(X,y1-1,-val);
T1.add(X,y2+1,-val);
}
else if(y1<=Y&&y2>=Y) {
if(x1<X) {
T1.add(x2,Y,val);
T1.add(x1-1,y1-1,val);
T1.add(x1-1,y2+1,val);
T1.add(x1-1,Y,-val);
T1.add(x2,y1-1,-val);
T1.add(x2,y2+1,-val);
}
else {
T1.add(x1,Y,val);
T1.add(x2+1,y1-1,val);
T1.add(x2+1,y2+1,val);
T1.add(x2+1,Y,-val);
T1.add(x1,y1-1,-val);
T1.add(x1,y2+1,-val);
}
}
else if(x1<=X&&x2>=X) {
if(y1<Y) {
T1.add(X,y2,val);
T1.add(x1-1,y1-1,val);
T1.add(x2+1,y1-1,val);
T1.add(X,y1-1,-val);
T1.add(x1-1,y2,-val);
T1.add(x2+1,y2,-val);
}
else {
T1.add(X,y1,val);
T1.add(x1-1,y2+1,val);
T1.add(x2+1,y2+1,val);
T1.add(X,y2+1,-val);
T1.add(x1-1,y1,-val);
T1.add(x2+1,y1,-val);
}
}
else if(x1<X&&y1<Y) {
T1.add(x2,y2,val);
T1.add(x1-1,y1-1,val);
T1.add(x1-1,y2,-val);
T1.add(x2,y1-1,-val);
}
else if(x1<X&&y1>Y) {
T1.add(x2,y1,val);
T1.add(x1-1,y2+1,val);
T1.add(x1-1,y1,-val);
T1.add(x2,y2+1,-val);
}
else if(x1>X&&y1<Y) {
T1.add(x1,y2,val);
T1.add(x2+1,y1-1,val);
T1.add(x1,y1-1,-val);
T1.add(x2+1,y2,-val);
}
else if(x1>X&&y1>Y) {
T1.add(x1,y1,val);
T1.add(x2+1,y2+1,val);
T1.add(x1,y2+1,-val);
T1.add(x2+1,y1,-val);
}
}
}
return 0;
}

递归版代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll; const int maxn=5e5+5; int n,m,X,Y,T;
ll a[maxn],b[maxn]; ll read() {
ll x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} ll gcd(ll a,ll b) {
if(!b)return abs(a);
return gcd(b,a%b);
} struct segment_tree_y {
int tot;
ll val[maxn<<2];
int ls[maxn<<2],rs[maxn<<2]; void build(int &p,int l,int r,int x) {
p=++tot;
if(l==r) {val[p]=a[(x-1)*m+l];return;}
int mid=(l+r)>>1;
build(ls[p],l,mid,x);
build(rs[p],mid+1,r,x);
val[p]=gcd(val[ls[p]],val[rs[p]]);
} void update(int &p1,int p2,int p3,int l,int r) {
p1=++tot;
if(l==r) {val[p1]=gcd(val[p2],val[p3]);return;}
int mid=(l+r)>>1;
update(ls[p1],ls[p2],ls[p3],l,mid);
update(rs[p1],rs[p2],rs[p3],mid+1,r);
val[p1]=gcd(val[ls[p1]],val[rs[p1]]);
} ll query(int p,int l,int r,int L,int R) {
if(L<=l&&r<=R)return val[p];
int mid=(l+r)>>1;ll res=0;
if(L<=mid)res=query(ls[p],l,mid,L,R);
if(R>mid)res=gcd(res,query(rs[p],mid+1,r,L,R));
return res;
} void add(int p,int l,int r,int pos,ll v) {
if(l==r) {val[p]+=v;return;}
int mid=(l+r)>>1;
if(pos<=mid)add(ls[p],l,mid,pos,v);
else add(rs[p],mid+1,r,pos,v);
val[p]=gcd(val[ls[p]],val[rs[p]]);
} void change(int p,int l,int r,int pos,ll v) {
if(l==r) {val[p]=v;return;}
int mid=(l+r)>>1;
if(pos<=mid)change(ls[p],l,mid,pos,v);
else change(rs[p],mid+1,r,pos,v);
val[p]=gcd(val[ls[p]],val[rs[p]]);
}
}T2; struct segment_tree_x {
int rt[maxn<<2]; void build(int p,int l,int r) {
if(l==r) {T2.build(rt[p],1,m,l);return;}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
T2.update(rt[p],rt[p<<1],rt[p<<1|1],1,m);
} ll query(int p,int l,int r,int x1,int x2,int y1,int y2) {
if(x1<=l&&r<=x2)return T2.query(rt[p],1,m,y1,y2);
int mid=(l+r)>>1;ll res=0;
if(x1<=mid)res=query(p<<1,l,mid,x1,x2,y1,y2);
if(x2>mid)res=gcd(res,query(p<<1|1,mid+1,r,x1,x2,y1,y2));
return res;
} void add(int p,int l,int r,int x,int y,ll v) {
if(x<1||x>n||y<1||y>m)return;
if(l==r) {T2.add(rt[p],1,m,y,v);return;}
int mid=(l+r)>>1;
if(x<=mid)add(p<<1,l,mid,x,y,v);
else add(p<<1|1,mid+1,r,x,y,v);
ll lv=T2.query(rt[p<<1],1,m,y,y);
ll rv=T2.query(rt[p<<1|1],1,m,y,y);
T2.change(rt[p],1,m,y,gcd(lv,rv));
}
}T1; int main() {
n=read(),m=read(),X=read(),Y=read(),T=read();
for(int i=1;i<=n*m;i++)a[i]=read();
for(int i=1;i<=n*m;i++) {
int pos=(i-1)%m+1;
if(pos<Y)b[i]=a[i]-a[i+1];
else if(pos>Y)b[i]=a[i]-a[i-1];
else b[i]=a[i];
}
for(int i=1;i<=n*m;i++) {
int pos=(i-1)/m+1;
if(pos<X)a[i]=b[i]-b[i+m];
else if(pos>X)a[i]=b[i]-b[i-m];
else a[i]=b[i];
}
T1.build(1,1,n);
while(T--) {
int opt=read(),x1=read(),y1=read(),x2=read(),y2=read();
if(!opt) {
x1=X-x1,x2=X+x2,y1=Y-y1,y2=Y+y2;
printf("%lld\n",T1.query(1,1,n,x1,x2,y1,y2));
}
if(opt) {
ll val=read();
if(x1<=X&&x2>=X&&y1<=Y&&y2>=Y) {
T1.add(1,1,n,X,Y,val);
T1.add(1,1,n,x1-1,y1-1,val);
T1.add(1,1,n,x1-1,y2+1,val);
T1.add(1,1,n,x2+1,y1-1,val);
T1.add(1,1,n,x2+1,y2+1,val);
T1.add(1,1,n,x1-1,Y,-val);
T1.add(1,1,n,x2+1,Y,-val);
T1.add(1,1,n,X,y1-1,-val);
T1.add(1,1,n,X,y2+1,-val);
}
else if(y1<=Y&&y2>=Y) {
if(x1<X) {
T1.add(1,1,n,x2,Y,val);
T1.add(1,1,n,x1-1,y1-1,val);
T1.add(1,1,n,x1-1,y2+1,val);
T1.add(1,1,n,x1-1,Y,-val);
T1.add(1,1,n,x2,y1-1,-val);
T1.add(1,1,n,x2,y2+1,-val);
}
else {
T1.add(1,1,n,x1,Y,val);
T1.add(1,1,n,x2+1,y1-1,val);
T1.add(1,1,n,x2+1,y2+1,val);
T1.add(1,1,n,x2+1,Y,-val);
T1.add(1,1,n,x1,y1-1,-val);
T1.add(1,1,n,x1,y2+1,-val);
}
}
else if(x1<=X&&x2>=X) {
if(y1<Y) {
T1.add(1,1,n,X,y2,val);
T1.add(1,1,n,x1-1,y1-1,val);
T1.add(1,1,n,x2+1,y1-1,val);
T1.add(1,1,n,X,y1-1,-val);
T1.add(1,1,n,x1-1,y2,-val);
T1.add(1,1,n,x2+1,y2,-val);
}
else {
T1.add(1,1,n,X,y1,val);
T1.add(1,1,n,x1-1,y2+1,val);
T1.add(1,1,n,x2+1,y2+1,val);
T1.add(1,1,n,X,y2+1,-val);
T1.add(1,1,n,x1-1,y1,-val);
T1.add(1,1,n,x2+1,y1,-val);
}
}
else if(x1<X&&y1<Y) {
T1.add(1,1,n,x2,y2,val);
T1.add(1,1,n,x1-1,y1-1,val);
T1.add(1,1,n,x1-1,y2,-val);
T1.add(1,1,n,x2,y1-1,-val);
}
else if(x1<X&&y1>Y) {
T1.add(1,1,n,x2,y1,val);
T1.add(1,1,n,x1-1,y2+1,val);
T1.add(1,1,n,x1-1,y1,-val);
T1.add(1,1,n,x2,y2+1,-val);
}
else if(x1>X&&y1<Y) {
T1.add(1,1,n,x1,y2,val);
T1.add(1,1,n,x2+1,y1-1,val);
T1.add(1,1,n,x1,y1-1,-val);
T1.add(1,1,n,x2+1,y2,-val);
}
else if(x1>X&&y1>Y) {
T1.add(1,1,n,x1,y1,val);
T1.add(1,1,n,x2+1,y2+1,val);
T1.add(1,1,n,x1,y2+1,-val);
T1.add(1,1,n,x2+1,y1,-val);
}
}
}
return 0;
}

BZOJ2877:[NOI2012]魔幻棋盘的更多相关文章

  1. BZOJ2877 NOI2012魔幻棋盘(二维线段树)

    显然一个序列的gcd=gcd(其差分序列的gcd,序列中第一个数).于是一维情况直接线段树维护差分序列即可. 容易想到将该做法拓展到二维.于是考虑维护二维差分,查询时对差分矩阵求矩形的gcd,再对矩形 ...

  2. [BZOJ2877][NOI2012]魔幻棋盘(二维线段树)

    https://blog.sengxian.com/solutions/bzoj-2877 注意二维线段树的upd()也是一个O(log n)的函数(pushdown()应该也是但没写过). #inc ...

  3. BZOJ2877 [Noi2012]魔幻棋盘

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  4. 【bzoj2877】 Noi2012—魔幻棋盘

    http://www.lydsy.com/JudgeOnline/problem.php?id=2877 (题目链接) 题意 一个${n*m}$的矩阵,维护两个操作:给任意子矩阵${+val}$:问某 ...

  5. 2877: [Noi2012]魔幻棋盘 - BZOJ

    DescriptionInput 第一行为两个正整数N,M,表示棋盘的大小. 第二行为两个正整数X,Y,表示棋盘守护者的位置. 第三行仅有一个正整数T,表示棋盘守护者将进行次操作. 接下来N行,每行有 ...

  6. NOI2012 魔幻棋盘

    http://www.lydsy.com/JudgeOnline/problem.php?id=2877 二维线段树. 好恶...... B类数据: 棋盘是一维的. 我们有一个结论: $gcd(a_{ ...

  7. 题解 洛谷 P2086 【[NOI2012]魔幻棋盘】

    先考虑只有一维的情况,要求支持区间加和求区间 \(\gcd\),根据 \(\gcd\) 的性质,发现: \[ \gcd(a_1,a_2,a_3,\ldots a_n)=\gcd(a_i,a_2-a_1 ...

  8. 数据结构(二维线段树,差分): NOI2012 魔幻棋盘

    貌似想复杂了…… #include <iostream> #include <cstring> #include <cstdio> #define mid ((l+ ...

  9. 【NOI2012】魔幻棋盘

    Description 将要读二年级的小 Q 买了一款新型益智玩具——魔幻棋盘,它是一个N行M列的网格棋盘,每个格子中均有一个正整数.棋盘守护者在棋盘的第X行Y列(行与列均从1开始编号) 并且始终不会 ...

随机推荐

  1. android开发系列之ContentObserver

    在这篇博客里面我想要分享一下自己最近在项目里面遇到一个比较好的数据同步解决方案,首先让我们先来看看该方案的应用场景:我们在客户端本地利用数据库缓存了一些数据,当我们检测到数据库里面的数据发生变化的时候 ...

  2. 安装Redis图形监控工具---RedisLive

    RedisLive简介 RedisLive是一款用Python编写基于WEB的Redis图形监控工具,也是一款实时监控Redis数据的开源软件,以WEB的形式展现出redis中的key的情况,实例数据 ...

  3. MyBatis缓存介绍

    一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 相同提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存.其存储作用域为 Se ...

  4. cocos2d-x 下使用加密 sqlite3

    sqlite3 加密库用的是wxsqlite3-3.0.0.1 提取出来的, 在android 下測试通过,无异常 编译时仅仅须要编译  sqlite3secure.c  此文件,即能够成功.測试时生 ...

  5. go module

    前言 go 1.5 引进了vendor管理工程依赖包,但是vendor的存放路径是在GOPATH底下,另外每个依赖还可以有自己的vendor,通常会弄得很乱,尽管dep管理工具可以将vendor平级化 ...

  6. EasyDSS RTMP流媒体服务器是怎样炼成的:Easy而且更加互联网!

    开发EasyDSS的初衷 自从12年开始做EasyDarwin的时候,当时眼光一直都仅仅局限在安防监控视频这一块,对RTMP没有太大的重视,对于后起之秀HLS更是没有太多关注,然而经历了15直播火热的 ...

  7. 使用struts2中默认的拦截器以及自定义拦截器

    转自:http://blog.sina.com.cn/s/blog_82f01d350101echs.html 如何使用struts2拦截器,或者自定义拦截器.特别注意,在使用拦截器的时候,在Acti ...

  8. adjA=(detA)A-1

    A–>adjA 连续性 反函数

  9. 我的Java开发学习之旅------>在Dos环境下Java内部类的编译和运行

    习惯了在IDE工具上进行代码编写,连最基本的Javac命令和Java命令都忘记的差不多了,今天对一个Java内部类进行编译和运行的时候,就出糗了.IDE是把双刃剑,它可以什么都帮你做了,你只要敲几行代 ...

  10. shell执行lua脚本传参数

    #lua test.lua 2 5arg[0]= test.lua arg[1]= 2arg[2]= 5 if arg[1] and arg[1] == "2" then prin ...