【BZOJ2683】简单题 [分治][树状数组]

简单题

Time Limit: 50 Sec  Memory Limit: 128 MB
[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。

Solution

  首先把询问拆成4个,那么我们就只要维护一个点左下角权值和了。

  然后对所有操作按照 x 升序排序。

  对 y 用个树状数组求前缀和,(由于 x 升序,所以此时询问已经相当于对y求前缀和了)

  以mid为分界线,考虑左区间对右区间的影响

  显然,我们可以把左区间的修改执行,然后执行右区间的询问

  这样我们就做完了这道题。

Code

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cmath>
  8 using namespace std;
  9 typedef long long s64;
 10
 11 const int ONE = 1000005;
 12 const int INF = 214748340;
 13
 14 int get()
 15 {
 16         int res = 1, Q = 1; char c;
 17         while( (c = getchar()) < 48 || c > 57)
 18             if(c == ‘-‘) Q = -1;
 19         if(Q) res = c - 48;
 20         while( (c = getchar()) >= 48 && c <= 57)
 21             res = res * 10 + c - 48;
 22         return res * Q;
 23 }
 24
 25 int n;
 26 namespace BIT
 27 {
 28         int C[ONE];
 29         int lowbit(int i) {return i & -i;}
 30         void Add(int R, int x)
 31         {
 32             for(int i = R; i <= n; i += lowbit(i))
 33                 C[i] += x;
 34         }
 35         int Query(int R)
 36         {
 37             int res = 0;
 38             for(int i = R; i >= 1; i -= lowbit(i))
 39                 res += C[i];
 40             return res;
 41         }
 42 }
 43
 44 int id, query_num, Ans[ONE];
 45 struct power
 46 {
 47         int id, opt, from;
 48         int x, y, val;
 49 }oper[ONE], q[ONE];
 50
 51 bool cmp(const power &a, const power &b)
 52 {
 53         if(a.x != b.x) return a.x < b.x;
 54         return a.opt < b.opt;
 55 }
 56
 57 void Deal(int x_1, int y_1, int x_2, int y_2)
 58 {
 59         query_num++;
 60         oper[++id] = (power){id, 2, query_num, x_2, y_2, 1};
 61         oper[++id] = (power){id, 2, query_num, x_1 - 1, y_1 - 1, 1};
 62         oper[++id] = (power){id, 2, query_num, x_1 - 1, y_2, -1};
 63         oper[++id] = (power){id, 2, query_num, x_2, y_1 - 1, -1};
 64 }
 65
 66 void Solve(int l, int r)
 67 {
 68         if(l >= r) return;
 69
 70         int mid = l + r >> 1;
 71         for(int i = l; i <= r; i++)
 72         {
 73             if(oper[i].opt == 1 && oper[i].id <= mid)
 74                 BIT::Add(oper[i].y, oper[i].val);
 75             if(oper[i].opt == 2 && oper[i].id > mid)
 76                 Ans[oper[i].from] += BIT::Query(oper[i].y) * oper[i].val;
 77         }
 78
 79         for(int i = l; i <= r; i++)
 80             if(oper[i].opt == 1 && oper[i].id <= mid)
 81                 BIT::Add(oper[i].y, -oper[i].val);
 82
 83         int tl = l, tr = mid + 1;
 84         for(int i = l; i <= r; i++)
 85             if(oper[i].id <= mid) q[tl++] = oper[i];
 86             else q[tr++] = oper[i];
 87
 88         for(int i = l; i <= r; i++)
 89             oper[i] = q[i];
 90
 91         Solve(l, mid), Solve(mid + 1, r);
 92 }
 93
 94 int opt, x_1, y_1, x_2, y_2;
 95
 96 int main()
 97 {
 98         n = get();
 99         for(;;)
100         {
101             opt = get();
102             if(opt == 3) break;
103             if(opt == 1)
104                 oper[++id].id = id, oper[id].opt = 1,
105                 oper[id].x = get(), oper[id].y = get(), oper[id].val = get();
106             if(opt == 2)
107                 x_1 = get(), y_1 = get(),
108                 x_2 = get(), y_2 = get(),
109                 Deal(x_1, y_1, x_2, y_2);
110         }
111
112         sort(oper + 1, oper + id + 1, cmp);
113
114         Solve(1, id);
115
116         for(int i = 1; i <= query_num; i++)
117             printf("%d\n", Ans[i]);
118 }

时间: 2024-11-05 16:26:40

【BZOJ2683】简单题 [分治][树状数组]的相关文章

BZOJ2683: 简单题(CDQ分治 + 树状数组)

BZOJ2683: 简单题(CDQ分治 + 树状数组) 题意: 你有一个\(N*N\)的棋盘,每个格子内有一个整数,初始时的时候全部为\(0\),现在需要维护两种操作: 命令 参数限制 内容 \(1\ x\ y\ A\) \(1\le x,y \le N\),A是正整数 将格子\(x,y\)里的数字加上\(A\) \(2\ x1\ y1\ x2\ y2\) \(1\le x1\le x2\le N,1\le y1\le y2\le N\) 输出\(x1\ y1\ x2\ y2\)这个矩形内的数字

BZOJ 2683 简单题 cdq分治+树状数组

题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后,二维的数据结构是显然不能过的,于是我们可能会考虑把一维排序之后另一位上数据结构什么的,然而cdq分治却能够很好的体现它的作用. 首先,对于每一个询问求和,显然是x在它左边的并且出现时间在它之前的所有的change对他可能会有影响. 我们按照x第一关键字,y第二关键字,操作第三关键字来排序所有的询问,然后在cdq的时候,每次递归处理左半区间,按照x动态的将y这一列的值加到树状数组里,来更新右半边的所有询问,注意这

HDU 5618:Jam&#39;s problem again(CDQ分治+树状数组处理三维偏序)

http://acm.hdu.edu.cn/showproblem.php?pid=5618 题意:-- 思路:和NEUOJ那题一样的.重新写了遍理解了一下,算作处理三维偏序的模板了. 1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 using namespace std; 6 #define INF 0x3f3f3f3f 7 #d

XJOI NOIP2015模拟赛Day1 T2 ctps bitset优化 或 排序+cdq分治+树状数组+平衡树

题意: 4维空间中有1个点集A,|A|=n,用(a,b,c,d)表示每个点. 共有m个询问,每次询问输入一个点(a,b,c,d),求最大的S,其中S={p|p∈A且ap<=a,bp<=b,cp<=c,dp<=d},输出|S| 输入格式: 第一行n 接下来n行有n个4维点对 第n+2行有一个数m 再接下来m行每行有一个四维点对,表示每个询问 输出格式: 对于每个询问输出一个数 **方法:**bitset优化 或 排序+cdq分治+树状数组+平衡树 解析: 神题,考场不会,暴力骗40,

【BZOJ4553】[Tjoi2016&amp;Heoi2016]序列 cdq分治+树状数组

[BZOJ4553][Tjoi2016&Heoi2016]序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可.注意:每种变化最多只有一个值发生变化.在样例输入1中,所有的变化是: 1 2 3 2 2 3 1 3 3 1

bzoj 1176 [Balkan2007]Mokia - CDQ分治 - 树状数组

Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Input 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小 接下来每行为一下三种输入之一(不包含引号): "1 x y a" "2 x1 y1 x2 y2" "3" 输入1:你需要把(x,y)(第x行第y列)的格子权值增加a 输入

BZOJ1176---[Balkan2007]Mokia (CDQ分治 + 树状数组)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1176 CDQ第一题,warush了好久.. CDQ分治推荐论文: 1 <从<Cash>谈一类分治算法的应用> 陈丹琦 2 <浅谈数据结构题的几个非经典解法>  许昊然 关于CDQ分治,两种要求:①操作不相互影响  ②可以离线处理 题目描述是有问题的,,初始时 全部为0,不是s 题意:二维平面内,两种操作,1 x y v ,位于(x,y)的值加上v...2 x1,

hdu_4918_Query on the subtree(树的分治+树状数组)

题目链接:hdu_4918_Query on the subtree 题意: 给出一颗n个点的树,每个点有一个权值,有两种操作,一种是将某个点的权值修改为v,另一种是查询距离点u不超过d的点的权值和. 题解: 这里可以去膜膜鸟神的博客. 简单来说就是对树的每个重心建立两个树状数组,然后对于每个点修改就在每个重心的BIT中去修改,查询也在每个重心的BIT中查询,然后容斥一下,就得出答案. 每种操作的复杂度为log2n,这题的细节比较多,具体看代码. 1 #include<bits/stdc++.h

BZOJ 3262: 陌上花开 cdq分治 树状数组

https://www.lydsy.com/JudgeOnline/problem.php?id=3262 cdq分治板子题,一维排序,一维分治(cdq里的队列),一维数据结构(树状数组). 学dp优化前来复习--以前好像写过这道题但是没写博客啊--在校oj上写的题都没怎么写博客,追悔莫及 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #