15813 魔幻棋盘 NOI2012

描述

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

  • (a)询问:他会以自己所在位置为基础,向四周随机扩展出一块大小不定的矩形区域,向你询问这一区域内所有数的最大公约数是多少。
  • (b)修改:他会随意挑选棋盘上的一块矩形区域,将这一区域内的所有数同时加上一个给定的整数。

游戏说明书上附有这样一句话“聪明的小朋友,当你连续答对 19930324 次询问后会得到一个惊喜噢!”。小 Q 十分想得到这个惊喜,于是每天都在玩这个玩具。但由于他粗心大意,经常算错数,难以达到这个目标。于是他来向你寻求帮助,希望你帮他写一个程序来回答棋盘守护者的询问,并保证 100% 的正确率。

为了简化问题,你的程序只需要完成棋盘守护者的 T 次操作,并且问题保证任何时刻棋盘上的数字均为不超过 262−1 的正整数。

输入描述

第一行为两个正整数 N,M,表示棋盘的大小。

第二行为两个正整数 X,Y,表示棋盘守护者的位置。

第三行仅有一个正整数 T,表示棋盘守护者将进行 T 次操作。

接下来 N 行,每行有 M 个正整数,用来描述初始时棋盘上每个位置的数。

接下来 T 行,按操作的时间顺序给出 T 次操作。每行描述一次操作,以一个数字 0 或 1 开头:

  • 若以数字 0 开头,表示此操作为询问,随后会有四个非负整数 x1​,y1​,x2​,y2​,表示询问的区域是以棋盘守护者的位置为基础向上扩展
    x1​ 行,向下扩展 x1​ 行,向左扩展 y1​ 列,向右扩展 y2​ 列得到的矩形区域(详见样例)。
  • 若以数字 1 开头,表示此操作为修改,随后会有四个正整数 x1​,y1​,x2​,y2​ 和一个整数 c,表示修改区域的上、下边界分别为第 x1​,x2​ 行,左、右边界分别为第 y1​,y2​ 列(详见样例),在此矩形区域内的所有数统一加上 c(注意 c 可能为负数)。

输出描述

对于每次询问操作,每行输出一个数,表示该区域内所有数的最大公约数。

样例输入 1

2 2
1 1
4
6 12
18 24
0 0 0 1 0
1 1 1 1 2 6
1 2 1 2 2 6
0 0 0 1 1

样例输出 1 

6
6

提示

数据范围与提示

对于第一、第四次操作(查询操作)后,加粗部分表示查询区域。

对于第二、第三次操作(修改操作)后,加粗部分表示修改区域。

测试数据分为 A、B、C 三类:

A 类数据占 20%,满足 N≤100,M≤100,T≤2×104。

B 类数据占 40%,满足 N=1,M≤5×105,T≤105。

C 类数据占 40%,满足 N×M≤5×105,T≤105。

在每类数据中,均有 50% 的数据满足每次修改操作仅含一个格子(即 x1​=x2​,y1​=y2​)。

输入数据保证满足题目描述中的所有性质。

题解 江湖老规矩:点个关注和赞再复制吧!!!麻烦各位了!!!^-^

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1000011;
int n,m,N,M,X[2],Y[2],cnt,rt,rt2,rt3;
LL lin[MAXN],CC,ans;
struct Array{
	LL shu[MAXN];
	LL* operator [] (int x) { return &shu[(x-1)*m]; }
}ju;
 
struct node{
	int ls,rs,l,r,tree;
	LL gcd;
}a[MAXN*3];
 
inline LL gcd(LL x,LL y){ if(y==0) return x; return gcd(y,x%y); }
 
inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
    if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
}
 
inline LL getlong(){
    LL w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
    if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
}
 
namespace One_D{
	struct node{
		int ls,rs,l,r;
		LL gcd;
	}a[MAXN*3];
 
	inline void build(int &k,int l,int r){
		if(!k) k=++cnt; int mid=(l+r)>>1; a[k].l=l; a[k].r=r;
		if(l==r) { a[k].gcd=lin[l]; return ; }
		build(a[k].ls,l,mid); build(a[k].rs,mid+1,r);
		a[k].gcd=gcd(a[a[k].ls].gcd,a[a[k].rs].gcd);
	}
 
	inline LL query(int k,int l,int r,int ql,int qr){
		if(ql>qr) return 0;
		if(ql<=l && r<=qr) return a[k].gcd; int mid=(l+r)>>1;
		if(ql>mid) return query(a[k].rs,mid+1,r,ql,qr);
		else if(qr<=mid) return query(a[k].ls,l,mid,ql,qr);
		else return gcd(query(a[k].ls,l,mid,ql,qr),query(a[k].rs,mid+1,r,ql,qr));
	}
 
	inline void modify(int k,int l,int r,int pos,LL val){
		if(l==r) { a[k].gcd+=val; return ; }
		int mid=(l+r)>>1; 
		if(pos<=mid) modify(a[k].ls,l,mid,pos,val); else modify(a[k].rs,mid+1,r,pos,val);
		a[k].gcd=gcd(a[a[k].ls].gcd,a[a[k].rs].gcd);
	}
}
 
namespace Seg_tree{
	inline void build(int &k,int l,int r,int bel){
		if(!k) k=++cnt; a[k].l=l; a[k].r=r;
		if(l==r) { a[k].gcd=ju[bel][l]; return ; }
		int mid=(l+r)>>1; build(a[k].ls,l,mid,bel); build(a[k].rs,mid+1,r,bel);
		a[k].gcd=gcd(a[a[k].ls].gcd,a[a[k].rs].gcd);
	}
 
	inline LL query(int k,int ql,int qr){
		if(ql>qr) return 0;
		if(ql<=a[k].l && a[k].r<=qr) return a[k].gcd;
		int mid=(a[k].l+a[k].r)>>1;
		if(ql>mid) return query(a[k].rs,ql,qr);
		else if(qr<=mid)/*!!!*/ return query(a[k].ls,ql,qr);
		else return gcd(query(a[k].ls,ql,qr),query(a[k].rs,ql,qr));
	}
 
	inline void modify(int k,int l,int r,int pos,LL val){
		if(l==r) { a[k].gcd+=val; return ; } int mid=(l+r)>>1;
		if(pos<=mid) modify(a[k].ls,l,mid,pos,val); else modify(a[k].rs,mid+1,r,pos,val);
		a[k].gcd=gcd(a[a[k].ls].gcd,a[a[k].rs].gcd);
	}
}
 
namespace Two_D{
	inline void merge(int &k,int lc,int rc){
		if(!k) k=++cnt; a[k].l=a[lc].l; a[k].r=a[lc].r;
		if(a[k].l==a[k].r) { a[k].gcd=gcd(a[lc].gcd,a[rc].gcd); return ; }
		merge(a[k].ls,a[lc].ls,a[rc].ls);
		merge(a[k].rs,a[lc].rs,a[rc].rs);
		a[k].gcd=gcd(a[a[k].ls].gcd,a[a[k].rs].gcd);
	}
 
	inline void build(int &k,int l,int r){
		if(!k) k=++cnt; a[k].l=l; a[k].r=r; if(l==r) { Seg_tree::build(a[k].tree,1,m,l); return ; }
		int mid=(l+r)>>1; build(a[k].ls,l,mid); build(a[k].rs,mid+1,r);
		merge(a[k].tree,a[a[k].ls].tree,a[a[k].rs].tree);
	}
 
	inline LL query(int k,int l,int r,int zuo,int you,int shang,int xia){
		if(zuo>you || shang>xia) return 0;
		if(zuo<=l && r<=you) return Seg_tree::query(a[k].tree,shang,xia);
		int mid=(l+r)>>1;
		if(zuo>mid) return query(a[k].rs,mid+1,r,zuo,you,shang,xia);
		else if(you<=mid) return query(a[k].ls,l,mid,zuo,you,shang,xia);
		else return gcd(query(a[k].rs,mid+1,r,zuo,you,shang,xia),query(a[k].ls,l,mid,zuo,you,shang,xia));
	}
 
	inline void modify(int k,int l,int r,int xx,int yy,LL val){
		if(l==r) { Seg_tree::modify(a[k].tree,1,m,yy,val); return ; } int mid=(l+r)>>1;
		if(xx<=mid) modify(a[k].ls,l,mid,xx,yy,val); else modify(a[k].rs,mid+1,r,xx,yy,val);
		LL lg=Seg_tree::query(a[a[k].ls].tree,yy,yy);
		LL rg=Seg_tree::query(a[a[k].rs].tree,yy,yy);
		LL nowg=Seg_tree::query(a[k].tree,yy,yy);
		nowg=gcd(lg,rg)-nowg;
		Seg_tree::modify(a[k].tree,1,m,yy,nowg);
	}
}
 
using namespace Two_D;
 
inline void work(){
	n=getint(); m=getint(); N=getint(); M=getint(); int T=getint();
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ju[i][j]=getlong();
 
	for(int i=1;i<=n;i++) {
		if(i==N) continue;
		for(int j=1;j<M-1;j++) ju[i][j]-=ju[i][j+1];
		for(int j=m;j>M+1;j--) ju[i][j]-=ju[i][j-1];
	}
 
	for(int j=1;j<=m;j++) {
		if(j==M) continue;
		for(int i=1;i<N-1;i++) ju[i][j]-=ju[i+1][j];
		for(int i=n;i>N+1;i--) ju[i][j]-=ju[i-1][j];
	}
 
	for(int j=1;j<M;j++) ju[N][j]-=ju[N][j+1];
	for(int j=m;j>M;j--) ju[N][j]-=ju[N][j-1];
	for(int i=1;i<=m;i++) lin[i]=ju[N][i];
	One_D::build(rt2,1,m);//build横向的
 
	for(int i=1;i<N;i++) ju[i][M]-=ju[i+1][M];
	for(int i=n;i>N;i--) ju[i][M]-=ju[i-1][M];
	for(int i=1;i<=n;i++) lin[i]=ju[i][M];
	One_D::build(rt3,1,n);//build纵向的
 
	for(int i=1;i<=m;i++) ju[N][i]=0;
	for(int i=1;i<=n;i++) ju[i][M]=0;
 
	build(rt,1,n);
	int ljh;
	while(T--) {
		ljh=getint();
 
		if(ljh==0) {//query
			X[0]=getint(); Y[0]=getint(); X[1]=getint(); Y[1]=getint();
			X[0]=N-X[0]; X[1]+=N; Y[0]=M-Y[0]; Y[1]+=M;
			ans=query(rt,1,n,X[0],X[1],Y[0],Y[1]);//query 2D
 
			if(X[0]<=N && N<=X[1] && Y[0]<=M && Y[1]>=M)
				ans=gcd(ans,One_D::query(rt2,1,m,Y[0],Y[1]));
			if(Y[0]<=M && M<=Y[1] && X[0]<=N && N<=X[1] )
				ans=gcd(ans,One_D::query(rt3,1,n,X[0],X[1]));
 
			ans=abs(ans);
			printf("%lld\n",ans);
		}
    else{
			X[0]=getint(); Y[0]=getint(); X[1]=getint(); Y[1]=getint(); CC=getlong();
			if(X[0]<=N && N<=X[1]) {
				if(Y[0]<=M && Y[1]<=M) {
					One_D::modify(rt2,1,m,Y[1],CC);
					if(Y[0]>1) One_D::modify(rt2,1,m,Y[0]-1,-CC);
					if(Y[1]==M && M<m) One_D::modify(rt2,1,m,M+1,-CC);/*!!!*/
				}
				else if(Y[0]>=M && Y[1]>=M) {
					One_D::modify(rt2,1,m,Y[0],CC);
					if(Y[1]<m) One_D::modify(rt2,1,m,Y[1]+1,-CC);
					if(Y[0]==M && M>1) One_D::modify(rt2,1,m,M-1,-CC);
				}
				else {
					One_D::modify(rt2,1,m,M,CC);
					if(Y[0]>1) One_D::modify(rt2,1,m,Y[0]-1,-CC);
					if(Y[1]<m) One_D::modify(rt2,1,m,Y[1]+1,-CC);
				}
			}
			if(Y[0]<=M && M<=Y[1]) {
				if(X[0]<=N && X[1]<=N) {
					One_D::modify(rt3,1,n,X[1],CC);
					if(X[0]>1) One_D::modify(rt3,1,n,X[0]-1,-CC);
					if(X[1]==N && N<n) One_D::modify(rt3,1,n,N+1,-CC);
				}
				else if(X[0]>=N && X[1]>=N) {
					One_D::modify(rt3,1,n,X[0],CC);
					if(X[1]<n) One_D::modify(rt3,1,n,X[1]+1,-CC);
					if(X[0]==N && N>1) One_D::modify(rt3,1,n,N-1,-CC);
				}
				else {
					One_D::modify(rt3,1,n,N,CC);
					if(X[0]>1) One_D::modify(rt3,1,n,X[0]-1,-CC);
					
					if(X[1]<n) One_D::modify(rt3,1,n,X[1]+1,-CC);
				}
			}
			if(X[0]<N && Y[0]<M) {
				if(X[0]>1 && Y[0]>1) modify(rt,1,n,X[0]-1,Y[0]-1,CC);
				if(N>1 && Y[0]>1) modify(rt,1,n,min(X[1],N-1),Y[0]-1,-CC);
				if(X[0]>1 && M>1) modify(rt,1,n,X[0]-1,min(Y[1],M-1),-CC);
				if(N>1 && M>1) modify(rt,1,n,min(N-1,X[1]),min(M-1,Y[1]),CC);
			}
 
			if(X[1]>N && Y[0]<M) {
				if(N<n && M>1) modify(rt,1,n,max(X[0],N+1),min(Y[1],M-1),CC);/*!!!*/
				if(N<n && Y[0]>1) modify(rt,1,n,max(X[0],N+1),Y[0]-1,-CC);
				if(X[1]<n && M>1) modify(rt,1,n,X[1]+1,min(Y[1],M-1)/*!!!*/,-CC);
				if(X[1]<n && Y[0]>1) modify(rt,1,n,X[1]+1,Y[0]-1,CC);
			}
 
			if(X[0]<N && Y[1]>M) {
				if(N>1 && M<m)/*!!!*/ modify(rt,1,n,min(X[1]/*!!!*/,N-1),max(Y[0],M+1),CC);
				if(M<m && X[0]>1) modify(rt,1,n,X[0]-1,max(Y[0]/*!!!*/,M+1),-CC);
				if(Y[1]<m && N>1/*!!!*/) modify(rt,1,n,min(X[1],N-1),Y[1]+1,-CC);
				if(X[0]>1 && Y[1]<m) modify(rt,1,n,X[0]-1,Y[1]+1,CC);
			}
 
			if(X[1]>N && Y[1]>M){
				if(N<n && M<m) modify(rt,1,n,max(X[0],N+1),max(Y[0],M+1),CC);
				if(X[1]<n && M<m/*!!!*/) modify(rt,1,n,X[1]+1,max(Y[0],M+1),-CC);
				if(N<n && Y[1]<m) modify(rt,1,n,max(X[0],N+1),Y[1]+1,-CC);
				if(X[1]<n && Y[1]<m) modify(rt,1,n,X[1]+1,Y[1]+1,CC);
			}
		}
	}
}
 
int main()
{
    work();
    return 0;
}

题目来源:千千蓝鲸

再重复一遍    江湖老规矩:

点个关注和赞再走吧,求求了!!! 麻烦各位了!!!^-^

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值