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开始编号) 并且始终不会 ...
随机推荐
- 【selenium】Selenium基于Python3的Web自动化测试脚本在IE上运行慢的解决方法
阐述问题: 执行自动化脚本时,发现文本输入在IE浏览器上特别慢,这样大大降低了自动化效率 解决办法:原因是原先下载的IEDriverServer.exe为64位系统的IE,换为32位的IEDriver ...
- sqlite3常用操作命令 和mysql的区别及优缺点
SQLite 的数据库权限只依赖于文件系统,没有用户帐户的概念. sqlite3 testdb.db .databases 命令查看数据库列表 create table tbl(name char(1 ...
- Drcom账户管理Server端解说
https://www.github.com/xiyouMc 首先今天要讲的是针对Drcom查询账户URL的解析和抓取数据. Drcom是大学生宿舍上网普遍使用的联网client,然而对于自己账 ...
- Android 异常解决方法【汇总】
(1)异常:Android中引入第三方Jar包的方法(Java.lang.NoClassDefFoundError解决办法) 1.在工程下新建lib文件夹,将需要的第三方包拷贝进来.2.将引用的第三方 ...
- Git 自己的一些工作中的总结
这个网址很重要:https://gitee.com/progit/2-Git-%E5%9F%BA%E7%A1%80.html#2.4-%E6%92%A4%E6%B6%88%E6%93%8D%E4%BD ...
- Unix环境高级编程—进程控制(三)
一.解释器文件 解释器文件属于文本文件,起始行形式为: #! pathname[optional-argument] 我们创建一个只有一行的文件如下: #!/home/webber/test/echo ...
- 搭建SVN服务器详细教程
搭建SVN服务器详细教程 本教程会从最基本的下载安装到上传代码,下载代码这条线来详细讲述如何完成SVN服务器的搭建 下载并安装VisualSVN server 下载并安装TortoiseSVN 导入项 ...
- 九度OJ 1065:输出梯形 (基础题)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5379 解决:2939 题目描述: 输入一个高度h,输出一个高为h,上底边为h的梯形. 输入: 一个整数h(1<=h<=1000 ...
- 在java项目中使用protobuf
1 通用方式 第一步,定义数据结构 第二步,使用protoc.exe生成java代码 第三步,序列化 第四步,反序列化 2 grpc方式 grpc官方推荐的方式,通过maven插件来生成java代码. ...
- intellij idea使用技巧
1 小窗口脱离了主窗口的解决办法 只要将floating mode和windowed mode取消掉就可以了,当选择上了floating mode和windowed mode之后会打一个勾,再次点击勾 ...