bzoj 2683 CDQ分治
题目描述
你有一个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 |
无 |
终止程序 |
输入格式
输入文件第一行一个正整数N。
接下来每行一个操作。
输出格式
对于每个2操作,输出一个对应的答案。
样例输入
4 1 2 3 3 2 1 1 3 3 1 2 2 2 2 2 2 3 4 3
样例输出
3 5
提示
1<=N<=500000,操作数不超过200000个,内存限制20M。
对于100%的数据,操作1中的A不超过2000。
思路分析 :
CDQ分治真有意思!
这个题目我们只需要将所给的条件变换一下,不就变成了一道裸的题目啦,题目所给的是在一个二维的空间中,我们可以加一维时间在上边,变成一个三维偏序。
代码示例 : (未测试)
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn = 6e5+5; int n; int k = 1; struct node { int x, y, z, num, sum; node(int _x=0, int _y=0, int _z=0, int _num=0, int _sum=0):x(_x),y(_y),z(_z),num(_num),sum(_sum){} bool operator< (const node &v)const{ if (x != v.x) return x < v.x; if (y != v.y) return y < v.y; return z < v.z; } }arr[maxn], f[maxn]; int c[maxn]; int lowbit(int x){return x&(-x);} void add(int p, int num){ for(int i = p; i <= n; i += lowbit(i)) c[i] += num; } int query(int x){ int res = 0; for(int i = x; i ; i -= lowbit(i)){ res += c[i]; } return res; } void CDQ(int l, int r){ if (l == r) return; int mid = (l+r)>>1; CDQ(l, mid); CDQ(mid+1, r); int p1 = l, p2 = mid+1; int num = 0; for(int i = l; i <= r; i++){ if (p1<=mid && (p2 > r || arr[p1].y <= arr[p2].y)){ add(arr[p1].z, arr[p1].num); f[num++] = arr[p1++]; } else { int num2 = query(arr[p2].z); arr[p2].sum += num2; f[num++] = arr[p2++]; } } num = 0; for(int i = l; i <= r; i++){ if (i <= mid) add(arr[i].z, -arr[i].num); arr[i] = f[num++]; } } vector<int>ve; int main () { int pt; int x1, y1, x2, y2, num; int time = 1; cin >> n; while(1){ scanf("%d", &pt); if (pt == 3) break; else if (pt == 1) { scanf("%d%d%d", &x1, &y1, &num); x1++, y1++; arr[k++] = node(time++, x1, y1, num, num); } else { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); x1++, y1++, x2++, y2++; ve.push_back(k); arr[k++] = node(time, x1-1, y1-1, 0, 0); arr[k++] = node(time, x1-1, y2, 0, 0); arr[k++] = node(time, x2, y1-1, 0, 0); arr[k++] = node(time++, x2, y2, 0, 0); } } CDQ(1, k-1);sort(arr+1, arr+k); for(int i = 0; i < ve.size(); i++){ int x = ve[i]; int ans = arr[x+3].sum+arr[x].sum-arr[x+1].sum-arr[x+2].sum; printf("%d\n", ans); } return 0; } /* 10 2 1 1 3 3 1 1 1 1 1 2 1 2 1 3 3 1 1 4 4 4 2 1 1 3 3 2 1 1 4 4 3 */
东北日出西边雨 道是无情却有情