BZOJ 2683: 简单题

2683: 简单题

Time Limit: 50 Sec  Memory Limit: 128 MB
Submit: 913  Solved: 379
[Submit][Status][Discuss]

Description

你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:

 

命令

参数限制

内容

1 x y A

1<=x,y<=N,A是正整数

将格子x,y里的数字加上A

2 x1 y1 x2 y2

1<=x1<= x2<=N

1<=y1<= y2<=N

输出x1 y1 x2 y2这个矩形内的数字和

3

终止程序

Input

输入文件第一行一个正整数N。
接下来每行一个操作。
 

Output

对于每个2操作,输出一个对应的答案。
 

Sample Input

4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

Sample Output

3
5

HINT

 

1<=N<=500000,操作数不超过200000个,内存限制20M。

对于100%的数据,操作1中的A不超过2000。

 

Source

 
[Submit][Status][Discuss]

 

分析

离线CDQ分治,对于预处理后的所有操作(查询)按照X坐标排序,然后用树状数组维护Y坐标上的前缀和。

 

代码

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 const int N = 500005;
  6 const int M = 200005;
  7 
  8 template <class T>
  9 __inline void read(T &x)
 10 {
 11     x = 0; 
 12     bool f = false;
 13     char c = getchar();
 14     
 15     while (c < '0')
 16     {
 17         if (c == '-')
 18             f ^= true;
 19         c = getchar();
 20     }
 21     
 22     while (c >= '0')
 23     {
 24         x = x*10 + c - '0';
 25         c = getchar();
 26     }
 27     
 28     if (f)x = -x;
 29 }
 30 
 31 struct operation
 32 {
 33     int id, op, to, x, y, d;
 34 }q[M << 2], tmp[M << 2];
 35 
 36 int cmp(const void *a, const void *b)
 37 {
 38     operation *A = (operation *)a;
 39     operation *B = (operation *)b;
 40     
 41     if (A->x != B->x)
 42         return A->x - B->x;
 43     if (A->y != B->y)
 44         return A->y - B->y;
 45     return A->op - B->op;
 46 }
 47 
 48 int n, m, t;
 49 
 50 void pushQuery(void)
 51 {
 52     int x1; read(x1);
 53     int y1; read(y1);
 54     int x2; read(x2);
 55     int y2; read(y2);
 56     
 57     ++t;
 58     {
 59         ++m; 
 60         q[m].d = 1;
 61         q[m].op = 2;
 62         q[m].id = m; 
 63         q[m].to = t; 
 64         q[m].x = x1 - 1;
 65         q[m].y = y1 - 1;
 66     }
 67     {
 68         ++m;
 69         q[m].d = 1;
 70         q[m].op = 2;
 71         q[m].id = m;
 72         q[m].to = t;
 73         q[m].x = x2;
 74         q[m].y = y2;
 75     }
 76     {
 77         ++m;
 78         q[m].d = -1;
 79         q[m].op = 2;
 80         q[m].id = m;
 81         q[m].to = t;
 82         q[m].y = y2;
 83         q[m].x = x1 - 1;
 84     }
 85     {
 86         ++m;
 87         q[m].d = -1;
 88         q[m].op = 2;
 89         q[m].id = m;
 90         q[m].to = t;
 91         q[m].x = x2;
 92         q[m].y = y1 - 1;
 93     }
 94 }
 95 
 96 int answer[M];
 97 
 98 void printAnswer(void)
 99 {
100     for (int i = 1; i <= t; ++i)
101         printf("%d\n", answer[i]);
102 }
103 
104 namespace binaryInsertTree
105 {
106     int tree[N];
107     
108     void change(int p, int v)
109     {
110         for (int i = p; i <= n; i += i & -i)
111             tree[i] += v;
112     }
113     
114     int query(int p)
115     {
116         int ret = 0;
117         
118         for (int i = p; i >= 1; i -= i & -i)
119             ret += tree[i];
120         
121         return ret;
122     }
123 }
124 
125 void divideAndConquer(int l, int r)
126 {
127     if (l != r)
128     {
129         int mid = (l + r) >> 1;
130         
131         for (int i = l; i <= r; ++i)
132         {
133             if (q[i].op == 1 && q[i].id <= mid)
134                 binaryInsertTree::change(q[i].y, q[i].d);
135             if (q[i].op == 2 && q[i].id > mid)
136                 answer[q[i].to] += binaryInsertTree::query(q[i].y) * q[i].d;
137         }
138         
139         for (int i = l; i <= r; ++i)
140             if (q[i].op == 1 && q[i].id <= mid)
141                 binaryInsertTree::change(q[i].y, -q[i].d);
142         
143         int t1 = l, t2 = mid + 1;
144         
145         for (int i = l; i <= r; ++i)
146         {
147             if (q[i].id <= mid)
148                 tmp[t1++] = q[i];
149             else
150                 tmp[t2++] = q[i];
151         }
152         
153         for (int i = l; i <= r; ++i)
154             q[i] = tmp[i];
155             
156         divideAndConquer(l, mid);
157         divideAndConquer(mid + 1, r);
158     }
159 }
160 
161 signed main(void)
162 {
163     read(n);
164     
165     for (m = t = 0; ; )
166     {
167         int opt; read(opt);
168         
169         if (opt == 3)break;
170         
171         switch (opt)
172         {
173             case 1 :
174                 ++m;
175                 q[m].op = 1;
176                 q[m].id = m;
177                 read(q[m].x);
178                 read(q[m].y);
179                 read(q[m].d);
180                 break;
181             case 2 :
182                 pushQuery();
183         }
184     }
185     
186     qsort(q + 1, m, sizeof(operation), cmp);
187     
188     divideAndConquer(1, m);
189     
190     printAnswer();
191 }
BZOJ_2683.cpp

 

@Author: YouSiki

posted @ 2016-11-17 14:12  YouSiki  阅读(291)  评论(0编辑  收藏  举报