[BZOJ1176][Balkan2007]Mokia cdq+树状数组

1176: [Balkan2007]Mokia

Time Limit: 30 Sec  Memory Limit: 162 MB
Submit: 3134  Solved: 1395
[Submit][Status][Discuss]

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

输入2:你需要求出以左下角为(x1,y1),右上角为(x2,y2)的矩阵内所有格子的权值和,并输出

输入3:表示输入结束

Output

对于每个输入2,输出一行,即输入2的答案

Sample Input

0 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

保证答案不会超过int范围

Source

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<algorithm>
 7 #define maxq 800000
 8 #define ll long long
 9 using namespace std;
10 struct data {ll id,x,y,tp,f,a,p;}t[maxq],tmp[maxq];
11 ll s,w;
12 ll ans[maxq];
13 int cnt;
14 bool cmp1(data t1,data t2) {return t1.x==t2.x?t1.id<t2.id:t1.x<t2.x;}
15 int ask;
16 ll sum[4000000];
17 int lowbit(int x) {return x&(-x);}
18 bool vis[maxq];
19 void insert(int x,ll ad) {for(int i=x;i<=w;i+=lowbit(i)) sum[i]+=ad;}
20 ll query(int x) {
21     ll re=0;
22     for(int i=x;i;i-=lowbit(i)) re+=sum[i];
23     return re;
24 }
25 void cdq(int l,int r) {
26     if(l==r) return;
27     int mid=l+r>>1;
28     int lp=l,rp=mid+1;
29     for(int i=l;i<=r;i++) {
30         if(t[i].tp==2) {
31             if(t[i].id>mid){ans[t[i].p]+=t[i].f*query(t[i].y);vis[t[i].p]=1;}
32          }
33         else {if(t[i].id<=mid) insert(t[i].y,t[i].a);}
34     }
35     for(int i=l;i<=r;i++) if(t[i].tp==1&&t[i].id<=mid) insert(t[i].y,-t[i].a);
36     for(int i=l;i<=r;i++) {
37         if(t[i].id<=mid) tmp[lp++]=t[i];
38         else tmp[rp++]=t[i];
39     }
40     for(int i=l;i<=r;i++) t[i]=tmp[i];
41     cdq(l,mid);cdq(mid+1,r);
42 }
43 void add(ll x1,ll y1,ll id,ll tp,ll f) {t[cnt].p=id;t[cnt].f=f;t[cnt].tp=tp;t[cnt].x=x1;t[cnt].y=y1;t[cnt].id=cnt;}
44 int main() {
45     scanf("%lld%lld",&s,&w);
46     int tp;
47     while(scanf("%d",&tp)) {
48         ask++;
49         if(tp==3) break;
50         if(tp==1) {cnt++;scanf("%lld%lld%lld",&t[cnt].x,&t[cnt].y,&t[cnt].a);t[cnt].id=cnt;t[cnt].tp=1;}
51         else {
52             ll x1,y1,x2,y2;
53             scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
54             cnt++;add(x1-1,y1-1,ask,2,1);cnt++;add(x2,y2,ask,2,1);
55             cnt++;add(x1-1,y2,ask,2,-1);cnt++;add(x2,y1-1,ask,2,-1);
56             ans[ask]+=(y2-y1+1)*(x2-x1+1)*s;
57         }
58     }
59     sort(t+1,t+cnt+1,cmp1);
60     cdq(1,cnt);
61     for(int i=1;i<=ask;i++) if(vis[i]) printf("%lld\n",ans[i]);
62 }

原文地址:https://www.cnblogs.com/wls001/p/8619185.html

时间: 2024-10-13 08:03:43

[BZOJ1176][Balkan2007]Mokia cdq+树状数组的相关文章

BZOJ1176: [Balkan2007]Mokia CDQ分治

最近很不对啊=w= 写程序全是bug啊 ans数组开小了竟然一直不知道,小数据没问题大数据拍不过,交上去RE 蛋疼半天 这个主要把每次询问拆成3个询问. #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<iostream> #define dout printf using namespace std; const int Maxw=

bzoj 2244 [SDOI2011]拦截导弹(dp+CDQ+树状数组)

传送门 题解 看了半天完全没发现这东西和CDQ有什么关系…… 先把原序列翻转,求起来方便 然后把每一个位置表示成$(a,b,c)$其中$a$表示位置,$b$表示高度,$c$表示速度,求有多少个位置$a,b,c$都小于它,这就是一个三维偏序问题,直接CDQ就可以解决了…… 然后考虑如何求第二问,就是一个导弹所在的LIS数/总的LIS数,因为一个导弹的LIS必须包含自己,以$g[i]$表示以$i$结尾的LIS总数,不难发现有如下转移式 $$g[i]=\sum g[j] \{ (i<j,h[i]<h

【bzoj 2716】[Violet 3]天使玩偶 (CDQ+树状数组)

题目描述 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它. 我们把 Ayu 生活的小镇看作一个二维平面坐标系,而 Ayu 会不定时地记起可能在某个点 (xmy) 埋下了天使玩偶:或者 Ayu 会询问你,假如她在 (x,y) ,那么她离近的天使玩偶可能埋下的地方有多远. 因为 Ayu 只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为dist(A,B)=|A

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

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

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 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

BZOJ 2244: [SDOI2011]拦截导弹 [CDQ分治 树状数组]

传送门 题意:三维最长不上升子序列以及每个元素出现在最长不上升子序列的概率 $1A$了好开心 首先需要从左右各求一遍,长度就是$F[0][i]+F[1][i]-1$,次数就是$G[0][i]*G[1][i]$ 我们可以用一些转换来简化代码 反转之后变成$LIS$,然后再反转并且$x,y$取反还是$LIS$,写一遍就可以啦 然后本题的树状数组需要维护最大值以及最大值的数量,还有一个时间戳 #include <iostream> #include <cstdio> #include &

bzoj2716 [ Violet 3 ] --cdq分治+树状数组

树状数组打错调了一个小时... 对于点(x,y),其它点只会在他的左下.右下.左上.右上四个方向上.我们只需求在左下方向上就可以了,因为其他方向可以通过改变相对位置求得. 考虑cdq分治.先按x坐标排序,然后将区间[l,r]分为[l,mid],[mid+1,r],因为只求左下方向上的点,所以可以去掉绝对值:dis=x+y-(x'+y') 只需求x'+y'最大的点就可以了.求(X,Y)时将[l,mid]中x值小于X的点的x+y值在树状数组中更新,然后查询y小于Y的最大的x+y,更新答案. 代码: