您的位置:首页 > 其它

bzoj2877: [Noi2012]魔幻棋盘 树套数+差分

2015-07-13 11:41 267 查看
神题,只能膜拜题解。然后发现了差分这个东西,所谓差分就是sigma{a[i]}=b[i]; a[i]=b[i]-b[i-1];(是不是和辗转相减很像。。。。。)

我们再来看一下二维的怎么做。。然后我们换一种维护的方法。因为题目要求一定会查询到守护者
a[x, y]
,所以我们以
(x, y)
为原点,建立直角座标系。二维的一样是得差分,对于第四象限的点:
b[i, j] = a[i, j] - a[i-1, j] - a[i, j-1] + a[i-1, j-1]
,其他三个象限类似。

所以对于定点(X,Y) 我们只需要维护其所在的那一行,和那一列的一维差分,和其它四个部分的二维差分。

区间更新的话,也只需要更新四个顶点就好了,因为是差分。然后二维线段去暴搞。

#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define getmid int mid=(l+r)>>1
#define maxn 555555
typedef long long sint;
int getint()
{
int res,f=1;char c;
while(c=getchar(),c<'0'||c>'9') {if(c=='-') f=-1;}
res=c-'0';
while(c=getchar(),c>='0'&&c<='9') res=res*10+c-'0';
return res*f;
}
sint getsint()
{
sint res,f=1;char c;
while(c=getchar(),c<'0'||c>'9') {if(c=='-') f=-1;}
res=c-'0';
while(c=getchar(),c>='0'&&c<='9') res=res*10+c-'0';
return res*f;
}
int n,m,x,y,t,x1,x2,y1,y2,opt;
sint d[maxn<<2],a[maxn<<2],s[2][maxn<<2],d1[maxn],d2[maxn],g[maxn<<4],c,ans;
sint gcd(sint a,sint b)
{
if(a<0) a=-a;if(b<0) b=-b;
if(a<b) swap(a,b);
if(b==0) return a;
return gcd(b,a%b);
}
int pos(int a,int b)
{
return (a-1)*m+b;
}
int pos2(int a,int b)
{
return (a-1)*(m*4+100)+b;
}
void upy(int rtx,int flag,int l,int r,int rt,int pos,sint v)
{
if(l==r)
{
if(flag)
{
g[pos2(rtx,rt)]=v;
}
else
{
g[pos2(rtx,rt)]=gcd(g[pos2(rtx<<1,rt)],g[pos2(rtx<<1|1,rt)]);
}
return;
}
getmid;
if(pos<=mid) upy(rtx,flag,lson,pos,v);
else upy(rtx,flag,rson,pos,v);
g[pos2(rtx,rt)]=gcd(g[pos2(rtx,rt<<1)],g[pos2(rtx,rt<<1|1)]);
}
void upx(int l,int r,int rt,int xx,int yy,sint v)
{
if(l==r)
{
upy(rt,1,1,m,1,yy,v);
return;
}
getmid;
if(xx<=mid) upx(lson,xx,yy,v);
else upx(rson,xx,yy,v);
upy(rt,0,1,m,1,yy,v);
}
void update(int flag,int l,int r,int rt,int pos,sint v)
{
if(l==r)
{
s[flag][rt]=v;
return;
}
getmid;
if(pos<=mid) update(flag,lson,pos,v);
else update(flag,rson,pos,v);
s[flag][rt]=gcd(s[flag][rt<<1],s[flag][rt<<1|1]);
}
sint query(int flag,int l,int r,int rt,int xx,int yy)
{
if(xx>yy) return 0;
if(xx<=l&&r<=yy)
{
return s[flag][rt];
}
getmid;
sint a=0,b=0;
if(xx<=mid) a=query(flag,lson,xx,yy);
if(yy>mid) b=query(flag,rson,xx,yy);
return gcd(a,b);
}
sint quy(int rtx,int l,int r,int rt,int xx,int yy)
{
if(xx<=l&&r<=yy)
{
return g[pos2(rtx,rt)];
}
getmid;
sint a=0,b=0;
if(xx<=mid) a=quy(rtx,lson,xx,yy);
if(yy>mid) b=quy(rtx,rson,xx,yy);
return gcd(a,b);
}
sint qux(int l,int r,int rt,int xx,int yy,int xx1,int yy1)
{
if (xx1>yy1||xx>yy) return 0;
if(xx<=l&&r<=yy)
{
return quy(rt,1,m,1,xx1,yy1);
}
getmid;
sint a=0,b=0;
if(xx<=mid) a=qux(lson,xx,yy,xx1,yy1);
if(yy>mid) b=qux(rson,xx,yy,xx1,yy1);
return gcd(a,b);
}
int main()
{
//freopen("chess1.in","r",stdin);
scanf("%d%d%d%d%d",&n,&m,&x,&y,&t);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
d[pos(i,j)]=getsint();
for(int i=1;i<n;i++)
{
for(int j=1;j<m;j++)
{
a[pos(i,j)]=d[pos(i,j)]-d[pos(i+1,j)]-d[pos(i,j+1)]+d[pos(i+1,j+1)];
upx(1,n,1,i,j,a[pos(i,j)]);
}
}
for(int i=1;i<n;i++)
{
d1[i]=d[pos(i+1,y)]-d[pos(i,y)];
update(0,1,n,1,i,d1[i]);
}
for(int i=1;i<m;i++)
{
d2[i]=d[pos(x,i+1)]-d[pos(x,i)];
update(1,1,m,1,i,d2[i]);
}
while(t--)
{
opt=getint();
x1=getint();y1=getint();
x2=getint();y2=getint();
if(opt==0)
{
ans=gcd(d[pos(x,y)],qux(1,n,1,x-x1,x+x2-1,y-y1,y+y2-1));
ans=gcd(ans,query(0,1,n,1,x-x1,x+x2-1));
ans=gcd(ans,query(1,1,m,1,y-y1,y+y2-1));
printf("%lld\n",ans);
}
else
{
c=getsint();
if(x1!=1&&y1!=1) upx(1,n,1,x1-1,y1-1,a[pos(x1-1,y1-1)]+=c);
if(x1!=1&&y2!=m) upx(1,n,1,x1-1,y2,a[pos(x1-1,y2)]-=c);
if(x2!=n&&y1!=1) upx(1,n,1,x2,y1-1,a[pos(x2,y1-1)]-=c);
if(x2!=n&&y2!=m) upx(1,n,1,x2,y2,a[pos(x2,y2)]+=c);
if (y1<=y&&y2>=y)
{
if (x1!=1) update(0,1,n,1,x1-1,d1[x1-1]+=c);
if (x2!=n) update(0,1,n,1,x2,d1[x2]-=c);
}
if (x1<=x&&x2>=x)
{
if (y1!=1) update(1,1,m,1,y1-1,d2[y1-1]+=c);
if (y2!=m) update(1,1,m,1,y2,d2[y2]-=c);
}
if(x1<=x&&x<=x2&&y1<=y&&y<=y2)
{
d[pos(x,y)]+=c;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: