【BZOJ 1176】 [Balkan2007]Mokia

2023-12-02 23:10
文章标签 bzoj 1176 balkan2007 mokia

本文主要是介绍【BZOJ 1176】 [Balkan2007]Mokia,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1176: [Balkan2007]Mokia

Time Limit: 30 Sec   Memory Limit: 162 MB
Submit: 736   Solved: 306
[ Submit][ Status]

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


CDQ分治模板题。


CDQ分治就是把一些修改,查询离线来做。


修改的先后顺序对结果没有影响,因此可以通过改变修改的顺序来降低时空复杂度。


若第k个操作是查询操作,我们只要把1-k-1中所有修改操作对k的影响计算出来,就能保证查询的正确性。


所以Solve(l,r)要做的就是让任意选择k(为查询操作),l-k-1的修改操作都被计算过了。




这道题因为空间限制,只能开一维树状数组,所以考虑CDQ分治。


先把子矩阵和转换为二维前缀和pre:

sum[x1,y1,x2,y2]=pre[x2,y2]-pre[x2,y1-1]-pre[x1-1,y2]+pre[x1-1,y1-1]


然后按照x排序,Solve(l,r)的时候计算(l,m)的修改对(m+1,r)上的查询的影响。然后再递归Solve(l,m) Solve(m+1,r)


接下来说明一下正确性

1.因为是按照x排序的,所以每个询问都只包含x小于他的所有修改,所以可以用一维


2.在递归的过程中,可以不重不漏的计算(1,k-1)中的修改对k的影响:Solve(l,r)先计算计算的是(l,m)的修改对(m+1,r)的影响;


假设k在(l,m)的某一位置,当前操作下没有对他进行修改,但是(l,k-1)的修改会在Solve(l,m)时对他进行计算,不会漏掉;


假设k在(m+1,r)的某一位置,(l,m)对他的影响刚刚算完了(Solve(l,r)),在Solve(m+1,r)的时候会递归计算出(m+1,k-1)对k的影响,因此l-k-1的修改对k的影响就都计算出来了。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 2000005
using namespace std;
struct data
{int x,y,pos,c,id,z;
}a[maxn],b[maxn];
int n,w,k,t,tot;
int s[maxn],ans[maxn];
bool cmp(data a,data b)
{return (a.x<b.x||(a.x==b.x&&a.pos<b.pos));
}
void Fz(int k,int aa,int b,int c)
{a[k].x=aa,a[k].y=b,a[k].z=c;
}
int lowbit(int x)
{return x&(-x);
}
void Add(int x,int v)
{for (int i=x;i<=w;i+=lowbit(i))s[i]+=v;
}
int Getsum(int x)
{int ans=0;for (int i=x;i;i-=lowbit(i))ans+=s[i];return ans;
}
void Solve(int l,int r)
{int m=(l+r)>>1;if (l==r) return;for (int i=l;i<=r;i++)  //计算(l,m)的修改操作对(m+1,r)的查询操作的影响{if (a[i].c==1&&a[i].pos<=m) Add(a[i].y,a[i].z);if (a[i].c!=1&&a[i].pos>m) ans[a[i].id]+=a[i].z*Getsum(a[i].y);}for (int i=l;i<=r;i++)   //消除当前影响if (a[i].pos<=m&&a[i].c==1) Add(a[i].y,-a[i].z);int t1=l,t2=m+1;for (int i=l;i<=r;i++)if (a[i].pos<=m) b[t1++]=a[i];else b[t2++]=a[i];for (int i=l;i<=r;i++)   //为递归计算做准备a[i]=b[i];Solve(l,m);Solve(m+1,r);t1=l,t2=m+1;for (int i=l;i<=r;i++)  //还原递归前的数组if ((a[t1].x<a[t2].x||t2>r)&&(t1<=m)) b[i]=a[t1++];else b[i]=a[t2++];for (int i=l;i<=r;i++)a[i]=b[i];
}
int main()
{scanf("%d%d",&k,&w);n=0;while (1){n++;scanf("%d",&a[n].c);if (a[n].c==3){n--;break;}if (a[n].c==1){scanf("%d%d%d",&a[n].x,&a[n].y,&a[n].z);}else{int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);ans[++tot]=(x2-x1+1)*(y2-y1+1)*k;Fz(n,x2,y2,1);Fz(++n,x1-1,y2,-1);Fz(++n,x2,y1-1,-1);Fz(++n,x1-1,y1-1,1);for (int i=n;i>=n-3;i--)a[i].id=tot;}}for (int i=1;i<=n;i++)a[i].pos=i;sort(a+1,a+1+n,cmp);Solve(1,n);for (int i=1;i<=tot;i++)printf("%d\n",ans[i]);return 0;
}
 



感悟:

目前对CDQ分治的理解就是:

有M次询问,按照给定顺序来算需要M次,而CDQ分治要算M*logM次,因此本题时间的复杂度为O(logW*MlogM)约为500万。


这篇关于【BZOJ 1176】 [Balkan2007]Mokia的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/447188

相关文章

【BZOJ】1324 Exca王者之剑 最大权独立集

传送门:【BZOJ】1324  Exca王者之剑 题目分析:赤裸裸的最大权独立集。。。最小割解决 代码如下: #include <cstdio>#include <vector>#include <cstring>#include <algorithm>using namespace std ;#define REP( i , a , b ) for ( int

【BZOJ】1026: [SCOI2009]windy数 数位DP

传送门:【BZOJ】1026: [SCOI2009]windy数 题目分析:数位DP水题。 代码如下: #include <stdio.h>#include <cstring>#include <algorithm>#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )#define For( i ,

【BZOJ】2152: 聪聪可可 点分治

传送门:【BZOJ】2152: 聪聪可可 题目分析:记录权值和%3的路径的个数。。。然后去重。。没了。。 代码如下: #include <vector>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std ;typedef lo

【高精度】-DLUTOJ-1176-大数乘法

题目链接:http://acm.dlut.edu.cn/problem.php?id=1176 题目描述:赤裸的大数乘法 解题思路: 突然想到自己没写过高精度乘法,就回咱们自己OJ上找出了这道题,赤裸的高精度乘法而已,没想到依然觉得不好写,准确说来是我从小到大算乘法的习惯使我产生了错觉:“ 想写大数乘法就得先写一个大数加法出来 ”。喂!我短路了半天才想明白,int 数组里可以存个两位数啊,再

【ACM】----杭电oj 1176

免费馅饼 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 28063    Accepted Submission(s): 9565 Problem Description 都说天上不会掉馅饼,但有一天gameboy正

BZOJ 2440 2301 莫比乌斯应用

http://www.lydsy.com/JudgeOnline/problem.php?id=2440 Description 小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些 数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而 这丝毫不影响他对其他数的热爱。  这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一 个小X讨厌

BZOJ 3732: Network(最小生成树+倍增)

题目链接 题意:给出一个图,每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少 很明显最终查询的边一定是在最小生成树里面的,先跑出最小生成树,然后,可以树链剖分,也可以使用倍增来计算 #include<bits/stdc++.h>using namespace std;#define cl(a,b) memset(a,b,sizeof(a))#define

BZOJ 2038 小Z的袜子(hose) (莫队离线)

题目地址:BZOJ 2038 裸的莫队算法。 代码如下: #include <iostream>#include <string.h>#include <math.h>#include <queue>#include <algorithm>#include <stdlib.h>#include <map>#include <set>#include <stdio.h>#in

BZOJ 2152 聪聪可可 (树上点分治)

题目地址:BZOJ 2152 找有多少对权值和为3的倍数的点。最简单的点分治。 代码如下: #include <iostream>#include <string.h>#include <math.h>#include <queue>#include <algorithm>#include <stdlib.h>#include <map>#include <set>#incl

BZOJ 3530 数数【AC自动机+数位dp】

[Sdoi2014]数数 简单数位dp+简单AC自动机 反正数位DP是队友写的 AC自动机要记录两个值,一个是是否为一个串的结束,即不合法状态,一个是前缀零的情况。 // whn6325689// Mr.Phoebe// http://blog.csdn.net/u013007900#include <algorithm>#include <iostr