zoukankan      html  css  js  c++  java
  • 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
    ",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
  • 相关阅读:
    windows的端口映射
    windows的ics
    关于windows的右键菜单项 注册表删除
    dig的使用 openwrt
    linux环境变量相关
    Difference between 2>&-, 2>/dev/null, |&, &>/dev/null and >/dev/null 2>&1
    openwrt ipv6
    ros资料参考
    ipv6的相关参考资料
    supervisor
  • 原文地址:https://www.cnblogs.com/maijing/p/4693715.html
Copyright © 2011-2022 走看看