NOI2012 魔幻棋盘

http://www.lydsy.com/JudgeOnline/problem.php?id=2877

二维线段树。

好恶。。。。。。

B类数据:

棋盘是一维的。

我们有一个结论:

$gcd(a_{1},a_{2},...,a_{n-1},a_{n})=gcd(a_{2}-a_{1},a_{3}-a_{2},...,a_{n}-a_{n-1},a_{1})$

证明:

假设集合A是a1,a2,...,an-1,an的所有公约数的集合,集合B是a2-a1,a3-a2,...,an-an-1,a1的所有公约数的集合。

对于所有的r∈A,r|a1,r|a2,...,r|an-1,r|an。

其必满足r|a2-a1,r|a3-a2,...,r|an-an-1,r|a1。

所以A⊆B。

对于所有的r∈B,r|a1,r|a2-a1,r|a3-a2,...,r|an-an-1。

其必满足:

∵r|a1,r|a2-a1

∴r|{a1-(a2-a1)}  ==>  r|-a2   ==> r|a2

 ∵r|a2,r|a3-a2

∴r|{a2-(a3-a2)}  ==>  r|-a3   ==> r|a3

......

∵r|an-1,r|an-an-1

∴r|{an-1 - (an - an-1)}  ==>  r|-an   ==> r|an

所以B⊆A。

故A=B。

所以:

$gcd(a_{1},a_{2},...,a_{n-1},a_{n})=gcd(a_{2}-a_{1},a_{3}-a_{2},...,a_{n}-a_{n-1},a_{1})$

我们记b[i]=a[i]-a[i-1]。

假设询问[l,R]中的最大公约数,其实就是求gcd(a[L],gcd(b[L+1]...b[R]))。

如果将[l,R]中数都加上C,其实就是a[L...R]加上C,b[L]加上C,b[R+1]减去C。

这可以用2棵线段树维护。

C类数据:

棋盘是二维的。

我们可以从一维推广一下。

原本是这样的:

$a_{4,1},a_{4,2},a_{4,3},a_{4,4}$
$a_{3,1},a_{3,2},a_{3,3},a_{3,4}$
$a_{2,1},a_{2,2},a_{2,3},a_{2,4}$
$a_{1,1},a_{1,2},a_{1,3},a_{1,4}$

 右减左:

$a_{4,1},a_{4,2}-a_{4,1},a_{4,3}-a_{4,2},a_{4,4}-a_{4,3}$

$a_{3,1},a_{3,2}-a_{3,1},a_{3,3}-a_{3,2},a_{3,4}-a_{3,3}$

$a_{2,1},a_{2,2}-a_{2,1},a_{2,3}-a_{2,2},a_{2,4}-a_{2,3}$

$a_{1,1},a_{1,2}-a_{1,1},a_{1,3}-a_{1,2},a_{1,4}-a_{1,3}$

上减下:

$a_{4,1}-a_{3,1},a_{4,2}-a_{4,1}-a_{3,2}+a_{3,1},a_{4,3}-a_{4,2}-a_{3,3}+a_{3,2},a_{4,4}-a_{4,3}-a_{3,4}+a_{3,3}$

$a_{3,1}-a_{2,1},a_{3,2}-a_{3,1}-a_{2,2}+a_{2,1},a_{3,3}-a_{3,2}-a_{2,3}+a_{2,2},a_{3,4}-a_{3,3}-a_{2,4}+a_{2,3}$

$a_{2,1}-a_{1,1},a_{2,2}-a_{2,1}-a_{1,2}+a_{1,1},a_{2,3}-a_{2,2}-a_{1,3}+a_{1,2},a_{2,4}-a_{2,3}-a_{1,4}+a_{1,3}$

$a_{1,1} , a_{1,2}-a_{1,1}, a_{1,3}-a_{1,2}, a_{1,4}-a_{1,3}$

其实就是变成了b[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1]

我们在原图中以(X,Y)为原点建立平面直角坐标系,将棋盘分成四部分,每个部分的操作时一样的。

1:

以(x1,y1)为左下角,(x2,y2)为右上角的矩形区域都加C。

我们发现只有(x1,y1),(x1,y2+1),(x2+1,y1),(x2+1,y2+1)发生了改变。

单点修改,可以用二维线段树。

注意在第一维线段树中,对于非叶子节点,我们更新的时候要要从子节点中得到更新。

2:

求以(1,1)为左下角,(x,y)为右上角的矩形区间的gcd。

直接在二维线段树中询问。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
 
using namespace std;

typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP;

#define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b)  for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define SF scanf
#define PF printf
#define two(k) (1<<(k))

template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}

const DB EPS=1e-9;
inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
const DB Pi=acos(-1.0);

inline int gint()
  {
        int res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z=='-'){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
        return (neg)?-res:res; 
    }
inline LL gll()
  {
      LL res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z=='-'){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
        return (neg)?-res:res; 
    }

const int maxN=500000;

int N,M,X,Y,T;
vector<LL> mp[maxN+1000];

inline LL gcd(LL a,LL b){LL ta,tb;if(a<0) a=-a;if(b<0) b=-b;for(;b!=0;ta=b,tb=a%b,a=ta,b=tb);return a;}

struct Tnode
  {
      Tnode *l,*r;LL v;
      inline Tnode(){l=r=0;v=0;}
      inline LL lv(){return l?l->v:0;}
      inline LL rv(){return r?r->v:0;}
  };
Tnode mem[10000000];
int MID=-1;
inline Tnode *New_Node(){mem[++MID]=Tnode();return mem+MID;}

struct Tdata
{
  
  int N,M;
    Tnode *root[4*maxN+1000];
    inline void clear(int _N,int _M){N=_N;M=_M;}
    
  inline void update1(Tnode *&rt,int l,int r,int x,LL C)
    {
          if(l>r || x<l || r<x) return;
          if(!rt) rt=New_Node();
        if(x<=l && r<=x){rt->v+=C;return;}
        int mid=(l+r)/2;
        if(x<=mid) update1(rt->l,l,mid,x,C); else update1(rt->r,mid+1,r,x,C);
        rt->v=gcd(rt->lv(),rt->rv());
    }
  inline void update2(Tnode *&rt,Tnode *&rtl,Tnode *&rtr,int l,int r,int x)
    {
        if(l>r || x<l || r<x) return;
        if(!rt) rt=New_Node();
        if(!rtl) rtl=New_Node();
        if(!rtr) rtr=New_Node();
        if(x<=l && r<=x){rt->v=gcd( rtl->v ,rtr->v ); return;}
        int mid=(l+r)/2;
        if(x<=mid)update2(rt->l,rtl->l,rtr->l,l,mid,x);else update2(rt->r,rtl->r,rtr->r,mid+1,r,x);
        rt->v=gcd(rt->lv(),rt->rv());
    }
  inline LL ask(Tnode *&rt,int l,int r,int x,int y)
    {
        if(l>r || x>y || r<x || y<l) return 0;
        if(!rt) return 0;
        if(x<=l && r<=y) return rt->v;
        int mid=(l+r)/2;
        return gcd( ask(rt->l,l,mid,x,y) , ask(rt->r,mid+1,r,x,y) );
    }
  
  inline LL ask(int rt,int l,int r,int x1,int y1,int x2,int y2)
    {
        if(l>r || x1>x2 || x2<l || r<x1) return 0;
            if(x1<=l && r<=x2) return ask(root[rt],1,M,y1,y2);
            int mid=(l+r)/2;
            return gcd( ask(rt*2,l,mid,x1,y1,x2,y2) , ask(rt*2+1,mid+1,r,x1,y1,x2,y2) );
        }
  inline void update(int rt,int l,int r,int x,int y,LL C)
    {
        if(l>r || x<l || r<x)return;
            int mid=(l+r)/2;
            if(l==r)
              update1(root[rt],1,M,y,C);
            else
              {
                if(x<=mid)update(rt*2,l,mid,x,y,C); else update(rt*2+1,mid+1,r,x,y,C);
                    update2(root[rt],root[rt*2],root[rt*2+1],1,M,y);
                }
    }
  
  inline LL xunwen(int x,int y)
    {
        return ask(1,1,N,1,1,x,y);
    }
  inline void xiugai(PII t1,PII t2,LL C)
    {
        int x1=t1.fi,y1=t1.se,x2=t2.fi,y2=t2.se;
        if(x1>x2)swap(x1,x2);
        if(y1>y2)swap(y1,y2);
            update(1,1,N,x1,y1,C);
            if(x2+1<=N)update(1,1,N,x2+1,y1,-C);
        if(y2+1<=M)update(1,1,N,x1,y2+1,-C);
            if(x2+1<=N && y2+1<=M)update(1,1,N,x2+1,y2+1,C);
    }
}data[4];

inline PII zhuan(int f,int i,int j)
  {
      switch(f)
        {
            case 0:return PII(j-Y+1,X-i+1);break;
            case 1:return PII(Y-j+1,X-i+1);break;
            case 2:return PII(Y-j+1,i-X+1);break;
            case 3:return PII(j-Y+1,i-X+1);break;
        }
  }

inline void build()
  {
      int i,j;
        data[0].clear(M-Y+1,X);
        re(i,1,X)re(j,Y,M)data[0].xiugai(zhuan(0,i,j),zhuan(0,i,j),mp[i][j]);
        data[1].clear(Y,X);
        re(i,1,X)re(j,1,Y)data[1].xiugai(zhuan(1,i,j),zhuan(1,i,j),mp[i][j]);
        data[2].clear(Y,N-X+1);
        re(i,X,N)re(j,1,Y)data[2].xiugai(zhuan(2,i,j),zhuan(2,i,j),mp[i][j]);
        data[3].clear(M-Y+1,N-X+1);
        re(i,X,N)re(j,Y,M)data[3].xiugai(zhuan(3,i,j),zhuan(3,i,j),mp[i][j]);
  }

int main()
  {
      freopen("chess.in","r",stdin);
      freopen("chess.out","w",stdout);
      int i,j;
      N=gint();M=gint();
      X=gint();Y=gint();
      T=gint();
      re(i,1,N){mp[i].push_back(0);re(j,1,M)mp[i].push_back(gll());mp[i].push_back(0);}
      re(j,0,M+1)mp[0].push_back(0),mp[N+1].push_back(0);
      build();
      while(T--)
        {
            int f=gint(),x1=gint(),y1=gint(),x2=gint(),y2=gint();
            LL C,res;
            switch(f)
              {
                  case 0:
                      res=0;
                      res=gcd(res,data[0].xunwen(y2+1,x1+1));
                      res=gcd(res,data[1].xunwen(y1+1,x1+1));
                      res=gcd(res,data[2].xunwen(y1+1,x2+1));
                      res=gcd(res,data[3].xunwen(y2+1,x2+1));
                      PF("%I64d\n",res);
                  break;
                  case 1:
                      C=gll();
                      if(x1<=X && y2>=Y) data[0].xiugai( zhuan(0,min(X,x2),max(Y,y1)) , zhuan(0,x1,y2) , C );
                      if(x1<=X && y1<=Y) data[1].xiugai( zhuan(1,min(X,x2),min(Y,y2)) , zhuan(1,x1,y1) , C );
                      if(x2>=X && y1<=Y) data[2].xiugai( zhuan(2,max(X,x1),min(Y,y2)) , zhuan(2,x2,y1) , C );
                      if(x2>=X && y2>=Y) data[3].xiugai( zhuan(3,max(X,x1),max(Y,y1)) , zhuan(3,x2,y2) , C );
                  break;
              }
        }
      return 0;
  }
View Code

 

posted @ 2015-08-01 11:16  maijing  阅读(478)  评论(0编辑  收藏  举报