[BZOJ2874]训练士兵

题目大意:
  给你一个n*m的矩阵,区间修改d次,区间询问q次。
  所有修改修完以后询问。

思路:
  不难想到一个二维线段树的做法。
  每次把当前平面分成四块,时间复杂度O(dp log_4(nm)),好像没什么问题。
  于是以为自己要A了。
  考完以后发现自己只有10分,90分MLE。连暴力都不如。
  算了一下空间复杂度,O(nm log_4(nm)),不爆才怪。
  这题正解是用主席树维护类似二维前缀和的东西。
  每次区间修改相当于对4个顶点修改。
  询问也是相当于对4个顶点询问。
  首先对所有修改的顶点排序按横坐标排序。
  考虑不同位置的修改对一个询问顶点作出的贡献。
  对于一个顶点(X,Y),左上、左下、右上、右下四个方向的不同顶点有不同的贡献。
  假设原点在左上角。
  那么在(X,Y)左上方的点,贡献为x*y*s。
  在(X,Y)左下方的点,贡献为x*Y*s。
  在(X,Y)右上方的点,贡献为X*y*s。
  在(X,Y)右下方的点,贡献为X*Y*s。
  对于每一个修改顶点,我们记录s、x*s、y*s、x*y*s的值,并用主席树维护。
  对于每个询问顶点,我们可以分左右两边讨论统计。

  1 #include<cstdio>
  2 #include<cctype>
  3 #include<vector>
  4 #include<algorithm>
  5 typedef unsigned long long qword;
  6 inline int getint() {
  7     register char ch;
  8     while(!isdigit(ch=getchar()));
  9     register int x=ch^'0';
 10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 11     return x;
 12 }
 13 const int D=40000,SIZE=4500000;
 14 struct Addition {
 15     int x,y,s;
 16     bool operator < (const Addition &another) const {
 17         return x<another.x||(x==another.x&&y<another.y);
 18     }
 19 };
 20 Addition a[D<<2|1];
 21 int cnt;
 22 inline void add_addition(const int &x,const int &y,const int &s) {
 23     if(!x||!y) return;
 24     a[++cnt]=(Addition){x,y,s};
 25 }
 26 int n,m,d,q;
 27 class FotileTree {
 28     private:
 29         struct Node {
 30             int left,right;
 31             qword s,xs,ys,xys;
 32         };
 33         Node node[SIZE];
 34         int sz,new_node() {
 35             return ++sz;
 36         }
 37         void push_up(const int &p) {
 38             node[p].s=node[node[p].left].s+node[node[p].right].s;
 39             node[p].xs=node[node[p].left].xs+node[node[p].right].xs;
 40             node[p].ys=node[node[p].left].ys+node[node[p].right].ys;
 41             node[p].xys=node[node[p].left].xys+node[node[p].right].xys;
 42         }
 43     public:
 44         int root[D<<2|1];
 45         int modify(const int &p,const int &b,const int &e,const int &x,const int &y,const int &s) {
 46             int new_p=new_node();
 47             node[new_p]=node[p];
 48             if(b==e) {
 49                 node[new_p].s+=s;
 50                 node[new_p].xs+=(qword)x*s;
 51                 node[new_p].ys+=(qword)y*s;
 52                 node[new_p].xys+=(qword)x*y*s;
 53                 return new_p;
 54             }
 55             const int mid=(b+e)>>1;
 56             if(y<=mid) node[new_p].left=modify(node[p].left,b,mid,x,y,s);
 57             if(y>mid) node[new_p].right=modify(node[p].right,mid+1,e,x,y,s);
 58             push_up(new_p);
 59             return new_p;
 60         }
 61         void query(const int &p1,const int &p2,const int &b,const int &e,const int &l,const int &r,qword &s,qword &xs,qword &ys,qword &xys) const {
 62             if(!p2) return;
 63             if(b==l&&e==r) {
 64                 s+=node[p2].s-node[p1].s;
 65                 xs+=node[p1].xs;
 66                 ys+=node[p2].ys-node[p1].ys;
 67                 xys+=node[p1].xys;
 68                 return;
 69             }
 70             const int mid=(b+e)>>1;
 71             if(l<=mid) query(node[p1].left,node[p2].left,b,mid,l,std::min(r,mid),s,xs,ys,xys);
 72             if(r>mid) query(node[p1].right,node[p2].right,mid+1,e,std::max(l,mid+1),r,s,xs,ys,xys);
 73         }
 74 };
 75 FotileTree t;
 76 inline qword query(const int &x,const int &y) {
 77     if(!x||!y) return 0;
 78     qword ans=0,s=0,xs=0,ys=0,xys=0;
 79     const int pos=std::upper_bound(&a[1],&a[cnt+1],(Addition){x,y,0})-&a[1];
 80     t.query(t.root[pos],t.root[cnt],1,m,1,y,s,xs,ys,xys);
 81     ans+=xys+ys*x;
 82     s=xs=ys=xys=0;
 83     if(y<m) t.query(t.root[pos],t.root[cnt],1,m,y+1,m,s,xs,ys,xys);
 84     ans+=xs*y+s*x*y;
 85     return ans;
 86 }
 87 int main() {
 88     n=getint(),m=getint(),d=getint(),q=getint();
 89     for(register int i=0;i<d;i++) {
 90         const int x1=getint(),x2=getint(),y1=getint(),y2=getint(),s=getint();
 91         add_addition(x1-1,y1-1,s);
 92         add_addition(x1-1,y2,-s);
 93         add_addition(x2,y1-1,-s);
 94         add_addition(x2,y2,s);
 95     }
 96     std::sort(&a[1],&a[cnt+1]);
 97     for(register int i=1;i<=cnt;i++) {
 98         const int x=a[i].x,y=a[i].y,s=a[i].s;
 99         t.root[i]=t.modify(t.root[i-1],1,m,x,y,s);
100     }
101     qword ans=0;
102     for(register int i=0;i<q;i++) {
103         int x1=ans%n+1,x2=(ans+getint())%n+1,y1=ans%m+1,y2=(ans+getint())%m+1;
104         if(x1>x2) std::swap(x1,x2);
105         if(y1>y2) std::swap(y1,y2);
106         printf("%llu\n",ans=query(x1-1,y1-1)-query(x1-1,y2)-query(x2,y1-1)+query(x2,y2));
107     }
108     return 0;
109 }

 

posted @ 2017-12-25 18:43  skylee03  阅读(159)  评论(0编辑  收藏  举报