[NOI2012]魔幻棋盘

这一道题的话就我而言可能更像数学里的分类讨论?

就是讨论一下修改矩形的四个角在守护者的哪边就好了,只是我的代码可能有点麻烦,如果有神犇看到的话能给点建议吗,拜谢!

然后很多东西我会放在代码里面,大佬们就看代码吧

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
#include <complex>
#include <stack>
#define LL long long int
#define dob double
#define FILE "chessa"
//#define FILE "魔幻棋盘"
using namespace std;
const int N = 500010;
int n,m,X,Y,q,rt,tot;
struct Array{//来自BOBOYANG的黑科技
  LL t[N];
  LL *operator [](int x){return &t[(x-1)*m];}
}A;
struct Tree{int l,r,ls,rs,tree;LL val;}T[N<<4];
inline LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
inline LL gi(){
  LL x=0,res=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
  while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  return x*res;
}
namespace Seg{
  inline void build(int &x,int l,int r,int id){
    x=++tot,T[x].l=l,T[x].r=r;int mid=(l+r)>>1;
    if(l==r){T[x].val=A[id][l];return;}
    build(T[x].ls,l,mid,id);build(T[x].rs,mid+1,r,id);
    T[x].val=gcd(T[T[x].ls].val,T[T[x].rs].val);
  }
  inline LL query(int x,int xl,int xr){
    int l=T[x].l,r=T[x].r,mid=(l+r)>>1;
    if(l==xl && r==xr)return T[x].val;
    if(xr<=mid)return query(T[x].ls,xl,xr);
    if(xl>mid)return query(T[x].rs,xl,xr);
    return gcd(query(T[x].ls,xl,mid),query(T[x].rs,mid+1,xr));
  }
  inline void update(int x,int xp,LL val){
    int l=T[x].l,r=T[x].r,mid=(l+r)>>1;
    if(l==r){T[x].val+=val;return;}
    if(xp<=mid)update(T[x].ls,xp,val);
    else update(T[x].rs,xp,val);
    T[x].val=gcd(T[T[x].ls].val,T[T[x].rs].val);
  }
}
namespace TwoD_Segment_Tree{
  inline void merge(int &x,int r1,int r2,int s,int t){
    if(!x)x=++tot,T[x].l=s,T[x].r=t;int mid=(s+t)>>1;
    if(s==t){T[x].val=gcd(T[r1].val,T[r2].val);return;}
    merge(T[x].ls,T[r1].ls,T[r2].ls,s,mid);
    merge(T[x].rs,T[r1].rs,T[r2].rs,mid+1,t);
    T[x].val=gcd(T[T[x].ls].val,T[T[x].rs].val);
  }
  inline void build(int &x,int s,int t){
    x=++tot;T[x].l=s;T[x].r=t;int mid=(s+t)>>1;
    if(s==t){Seg::build(T[x].tree,1,m,s);return;}
    build(T[x].ls,s,mid);build(T[x].rs,mid+1,t);
    merge(T[x].tree,T[T[x].ls].tree,T[T[x].rs].tree,1,m);
  }
  inline LL query(int x,int x1,int x2,int y1,int y2){
    int l=T[x].l,r=T[x].r,mid=(l+r)>>1;
    if(l==x1 && r==x2)return Seg::query(T[x].tree,y1,y2);
    if(x2<=mid)return query(T[x].ls,x1,x2,y1,y2);
    if(x1>mid)return query(T[x].rs,x1,x2,y1,y2);
    return gcd(query(T[x].ls,x1,mid,y1,y2),query(T[x].rs,mid+1,x2,y1,y2));
  }
  inline void update(int x,int xp,int y,LL val){
    int l=T[x].l,r=T[x].r,mid=(l+r)>>1;
    if(l==r){Seg::update(T[x].tree,y,val);return;}
    if(xp<=mid)update(T[x].ls,xp,y,val);
    else update(T[x].rs,xp,y,val);
    LL lval=Seg::query(T[T[x].ls].tree,y,y);
    LL rval=Seg::query(T[T[x].rs].tree,y,y);
    LL mval=Seg::query(T[x].tree,y,y);
    Seg::update(T[x].tree,y,gcd(lval,rval)-mval);
  }
}
using namespace TwoD_Segment_Tree;
int main()
{
  n=gi();m=gi();X=gi();Y=gi();q=gi();
  for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
      A[i][j]=gi();
  for(int i=1;i<=n;++i){
    for(int j=1;j<Y;++j)A[i][j]-=A[i][j+1];
    for(int j=m;j>Y;--j)A[i][j]-=A[i][j-1];
  }
  for(int j=1;j<=m;++j){
    for(int i=1;i<X;++i)A[i][j]-=A[i+1][j];
    for(int i=n;i>X;--i)A[i][j]-=A[i-1][j];
  }
  build(rt,1,n);
  for(int t=1,type,x1,y1,x2,y2;t<=q;++t){
    scanf("%d%d%d%d%d",&type,&x1,&y1,&x2,&y2);
    if(type==0){
      x1=X-x1;y1=Y-y1;x2=X+x2;y2=Y+y2;
      printf("%lld
",abs(query(rt,x1,x2,y1,y2)));
    }
    if(type==1){
      LL val=gi();
      //讨论修改矩形的四个角在守护者的哪边。
      //左上角(x1,y1)
      /*在守护者左上*/if(x1<=X && y1<=Y && x1>1 && y1>1)update(rt,x1-1,y1-1,val);
      /*在守护者右上*/if(x1<=X && y1>Y && x1>1)update(rt,x1-1,y1,-val);
      /*在守护者左下*/if(x1>X && y1<=Y && y1>1)update(rt,x1,y1-1,-val);
      /*在守护者右下*/if(x1>X && y1>Y)update(rt,x1,y1,val);
      //右上角(x1,y2)
      /*在守护者左上*/if(x1<=X && y2<Y && x1>1)update(rt,x1-1,y2,-val);
      /*在守护者右上*/if(x1<=X && y2>=Y && x1>1 && y2<m)update(rt,x1-1,y2+1,val);
      /*在守护者左下*/if(x1>X && y2<Y)update(rt,x1,y2,val);
      /*在守护者右下*/if(x1>X && y2>=Y && y2<m)update(rt,x1,y2+1,-val);
      //左下角(x2,y1)
      /*在守护者左上*/if(x2<X && y1<=Y && y1>1)update(rt,x2,y1-1,-val);
      /*在守护者右上*/if(x2<X && y1>Y)update(rt,x2,y1,val);
      /*在守护者左下*/if(x2>=X && y1<=Y && x2<n && y1>1)update(rt,x2+1,y1-1,val);
      /*在守护者右下*/if(x2>=X && y1>Y && x2<n)update(rt,x2+1,y1,-val);
      //右下角(x2,y2)
      /*在守护者左上*/if(x2<X && y2<Y)update(rt,x2,y2,val);
      /*在守护者右上*/if(x2<X && y2>=Y && y2<m)update(rt,x2,y2+1,-val);
      /*在守护者左下*/if(x2>=X && y2<Y && x2<n)update(rt,x2+1,y2,-val);
      /*在守护者右下*/if(x2>=X && y2>=Y && x2<n && y2<m)update(rt,x2+1,y2+1,val);
      //讨论修改矩形的四条边跨守护者十字情况。
      //矩形竖边对守护者横线的影响
      if(x1<=X && x2>=X){
        //左边(x1,y1) -> (x2,y1)
        /*跨左横线*/if(y1<=Y && y1>1)update(rt,X,y1-1,-val);
        /*跨右横线*/if(y1>Y)update(rt,X,y1,val);      
        //右边(x1,y2) -> (x2,y2)
        /*跨左横线*/if(y2<Y)update(rt,X,y2,val);
        /*跨右横线*/if(y2>=Y && y2<m)update(rt,X,y2+1,-val);
      }
      //矩形横边对守护者竖线的影响
      if(y1<=Y && y2>=Y){
        //上边(x1,y1) -> (x1,y2)
        /*跨上竖线*/if(x1<=X && x1>1)update(rt,x1-1,Y,-val);
        /*跨下竖线*/if(x1>X)update(rt,x1,Y,val);
        //下边(x2,y1) -> (x2,y2)
        /*跨上竖线*/if(x2<X)update(rt,x2,Y,val);
        /*跨下竖线*/if(x2>=X && x2<n)update(rt,x2+1,Y,-val);
      }      
      if(x1<=X && x2>=X && y1<=Y && y2>=Y)update(rt,X,Y,val);
    }
  }
  return 0;
}
原文地址:https://www.cnblogs.com/zi-nai-boboyang/p/11437182.html