BZOJ2877:[NOI2012]魔幻棋盘
浅谈树状数组与主席树: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]魔幻棋盘的更多相关文章
- BZOJ2877 NOI2012魔幻棋盘(二维线段树)
显然一个序列的gcd=gcd(其差分序列的gcd,序列中第一个数).于是一维情况直接线段树维护差分序列即可. 容易想到将该做法拓展到二维.于是考虑维护二维差分,查询时对差分矩阵求矩形的gcd,再对矩形 ...
- [BZOJ2877][NOI2012]魔幻棋盘(二维线段树)
https://blog.sengxian.com/solutions/bzoj-2877 注意二维线段树的upd()也是一个O(log n)的函数(pushdown()应该也是但没写过). #inc ...
- BZOJ2877 [Noi2012]魔幻棋盘
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 【bzoj2877】 Noi2012—魔幻棋盘
http://www.lydsy.com/JudgeOnline/problem.php?id=2877 (题目链接) 题意 一个${n*m}$的矩阵,维护两个操作:给任意子矩阵${+val}$:问某 ...
- 2877: [Noi2012]魔幻棋盘 - BZOJ
DescriptionInput 第一行为两个正整数N,M,表示棋盘的大小. 第二行为两个正整数X,Y,表示棋盘守护者的位置. 第三行仅有一个正整数T,表示棋盘守护者将进行次操作. 接下来N行,每行有 ...
- NOI2012 魔幻棋盘
http://www.lydsy.com/JudgeOnline/problem.php?id=2877 二维线段树. 好恶...... B类数据: 棋盘是一维的. 我们有一个结论: $gcd(a_{ ...
- 题解 洛谷 P2086 【[NOI2012]魔幻棋盘】
先考虑只有一维的情况,要求支持区间加和求区间 \(\gcd\),根据 \(\gcd\) 的性质,发现: \[ \gcd(a_1,a_2,a_3,\ldots a_n)=\gcd(a_i,a_2-a_1 ...
- 数据结构(二维线段树,差分): NOI2012 魔幻棋盘
貌似想复杂了…… #include <iostream> #include <cstring> #include <cstdio> #define mid ((l+ ...
- 【NOI2012】魔幻棋盘
Description 将要读二年级的小 Q 买了一款新型益智玩具——魔幻棋盘,它是一个N行M列的网格棋盘,每个格子中均有一个正整数.棋盘守护者在棋盘的第X行Y列(行与列均从1开始编号) 并且始终不会 ...
随机推荐
- ReactNative Navigator
https://facebook.github.io/react-native/docs/navigator.html Navigator实现了页面之间的跳转. Demo描述:打开即进入“课程”页面, ...
- 身份证归属地查询免费api接口代码
描写叙述 :依据身份证编号 查询归属地信息. 身份证实体类: package org.wx.xhelper.model; /** * 身份证实体类 * @author wangxw * @versio ...
- 1-1:CSS3课程入门之属性选择器
div[name=jewave] 选取属性名为name且属性值是"jewave"的元素 div[name^=jewave]选取属性名为name且属性值以"jewave&q ...
- cacti 安装和组件添加
安装cacti 步骤 1.准备lamp环境 2.准备所需包:rrdtool(绘图) cacti(安装程序) net-snmpd(数据收集) 3.安装所需库文件 rrdtool所需库文件有: cairo ...
- 查看SELinux状态并关闭SELinux
SELinux(Security-Enhanced Linux)是Linux上最杰出的新安全子系统.在linux内核级别上提供了一个灵活的强制访问控制系统(MAC),这个强制访问控制系统是建立在自由访 ...
- hadoop 出现FATAL conf.Configuration: error parsing conf file,异常
FATAL conf.Configuration: error parsing conf file: com.sun.org.apache.xerces.internal.impl.io.Malfor ...
- 苹果开发之COCOA编程(第三版)下半部分
第十八章:Image和鼠标事件 1.NSResponderNSView继承自NSResponder类.所有的事件处理方法都定义在NSResponder类中.NSResponder申明了如下方法:- ( ...
- TP框架---thinkphp修改删除数据
1.在控制器MainController里面写一个方法,调用Nation表中的数据. public function zhuyemian() { $n = D("Nation"); ...
- 【BZOJ3956】Count 主席树+单调栈
[BZOJ3956]Count Description Input Output Sample Input 3 2 0 2 1 2 1 1 1 3 Sample Output 0 3 HINT M,N ...
- (*)(转)要快速学习SSM框架,你需要一套学习曲线平滑的教程
作者:meepo链接:https://www.zhihu.com/question/57719761/answer/156952139来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...