zoukankan      html  css  js  c++  java
  • BZOJ2874 : 训练士兵

    设$a[i][j]$表示$(i,j)$右下角要增加多少

    $aj[i][j]=a[i][j] imes j$

    $ai[i][j]=a[i][j] imes i$

    $aij[i][j]=a[i][j] imes i imes j$

    则查询$(x,y)$左上角内的权值和时,

    答案$=(x+1)(y+1)ask_{a}(x,y)-(x+1)ask_{aj}(x,y)-(y+1)ask_{ai}(x,y)+ask_{aij}(x,y)$。

    首先将坐标离散化,将修改拆成4个单点修改,然后从左往右插入点,用可持久化线段树维护二维前缀和。

    查询时拆成4次二维前缀和查询即可。

    时间复杂度$O((k+q)log k)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=80010,M=3000000;
    int n,m,k,q,i,j,x,y,X1,X2,Y1,Y2,s,cnt,bx[N],by[N],cl,g[N],nxt[N<<1];ll ans;
    struct P{int x,y,z;P(){}P(int _x,int _y,int _z){x=_x,y=_y,z=_z;}}a[N<<1];
    int tot,T[N],l[M],r[M];
    struct V{
      ll o,j,i,ij;
      V(){o=j=i=ij=0;}
      V(ll _o,ll _j,ll _i,ll _ij){o=_o,j=_j,i=_i,ij=_ij;}
      V(int x,int y,int z){o=z,j=1LL*z*y,i=1LL*z*x,ij=1LL*z*x*y;}
      inline V operator+(const V&b){return V(o+b.o,j+b.j,i+b.i,ij+b.ij);}
    }v[M],p;
    inline int lowerx(int x){
      int l=1,r=cl,mid,t=0;
      while(l<=r)if(bx[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
      return t;
    }
    inline int lowery(int x){
      int l=1,r=cl,mid,t=0;
      while(l<=r)if(by[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
      return t;
    }
    int ins(int x,int a,int b,int c){
      int y=++tot;
      v[y]=v[x]+p;
      if(a==b)return y;
      int mid=(a+b)>>1;
      if(c<=mid)l[y]=ins(l[x],a,mid,c),r[y]=r[x];else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c);
      return y;
    }
    ll asko(int x,int a,int b,int d){
      if(!x||!d)return 0;
      if(b<=d)return v[x].o;
      int mid=(a+b)>>1;
      ll t=asko(l[x],a,mid,d);
      if(d>mid)t+=asko(r[x],mid+1,b,d);
      return t;
    }
    ll askj(int x,int a,int b,int d){
      if(!x||!d)return 0;
      if(b<=d)return v[x].j;
      int mid=(a+b)>>1;
      ll t=askj(l[x],a,mid,d);
      if(d>mid)t+=askj(r[x],mid+1,b,d);
      return t;
    }
    ll aski(int x,int a,int b,int d){
      if(!x||!d)return 0;
      if(b<=d)return v[x].i;
      int mid=(a+b)>>1;
      ll t=aski(l[x],a,mid,d);
      if(d>mid)t+=aski(r[x],mid+1,b,d);
      return t;
    }
    ll askij(int x,int a,int b,int d){
      if(!x||!d)return 0;
      if(b<=d)return v[x].ij;
      int mid=(a+b)>>1;
      ll t=askij(l[x],a,mid,d);
      if(d>mid)t+=askij(r[x],mid+1,b,d);
      return t;
    }
    inline ll sum(int x,int y){
      int i=lowerx(x),j=lowery(y);
      return asko(T[i],1,cl,j)*(x+1)*(y+1)-askj(T[i],1,cl,j)*(x+1)-aski(T[i],1,cl,j)*(y+1)+askij(T[i],1,cl,j);
    }
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    int main(){
      read(n),read(m),read(k),read(q);
      while(k--){
        read(X1),read(X2),read(Y1),read(Y2),read(s);
        a[++cnt]=P(X1,Y1,s);
        a[++cnt]=P(X2+1,Y1,-s);
        a[++cnt]=P(X1,Y2+1,-s);
        a[++cnt]=P(X2+1,Y2+1,s);
        bx[++cl]=X1,by[cl]=Y1,bx[++cl]=X2+1,by[cl]=Y2+1;
      }
      sort(bx+1,bx+cl+1),sort(by+1,by+cl+1);
      for(i=1;i<=cnt;i++)nxt[i]=g[a[i].x=lowerx(a[i].x)],g[a[i].x]=i;
      for(i=1;i<=cl;i++)for(T[i]=T[i-1],j=g[i];j;j=nxt[j])p=V(bx[i],a[j].y,a[j].z),T[i]=ins(T[i],1,cl,lowery(a[j].y));
      while(q--){
        read(x),read(y);
        X1=ans%n+1,X2=(ans+x)%n+1;if(X1>X2)swap(X1,X2);
        Y1=ans%m+1,Y2=(ans+y)%m+1;if(Y1>Y2)swap(Y1,Y2);
        printf("%lld
    ",ans=sum(X2,Y2)-sum(X1-1,Y2)-sum(X2,Y1-1)+sum(X1-1,Y1-1));
      }
      return 0;
    }
    

      

  • 相关阅读:
    python 并发编程 多线程 event
    python 并发编程 多线程 定时器
    python 并发编程 多线程 信号量
    linux top 查看CPU命令
    python 并发编程 多线程 GIL与多线程
    python 并发编程 多线程 死锁现象与递归锁
    python 并发编程 多线程 GIL与Lock
    python GIL全局解释器锁与互斥锁 目录
    python 并发编程 多线程 GIL全局解释器锁基本概念
    执行python程序 出现三部曲
  • 原文地址:https://www.cnblogs.com/clrs97/p/4856632.html
Copyright © 2011-2022 走看看