【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万。

时间: 2024-09-29 10:52:38

【BZOJ 1176】 [Balkan2007]Mokia的相关文章

【BZOJ 1176】【Balkan 2007】Mokia

http://www.lydsy.com/JudgeOnline/problem.php?id=1176 整体二分的例题 把每个询问拆成四个询问,整体二分里x坐标递增,按x坐标扫的时候用树状数组维护y坐标前缀和. 一开始想复杂了,按cdq分治先solve左边再处理中间再solve右边,这样每次都要对x坐标排序,常数巨大,T了好几次TwT 后来参考了别人的代码,发现自己一开始就想复杂了.这道题不需要在solve完后还是保持原来的按x坐标递增的顺序,也不需要先处理出左边的信息才能更新右边的信息. 这

【BZOJ 2820】 YY的GCD

2820: YY的GCD Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 807  Solved: 404 [Submit][Status] Description 神犇YY虐完数论后给傻×kAc出了一题 给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对 kAc这种傻×必然不会了,于是向你来请教-- 多组输入 Input 第一行一个整数T 表述数据组数 接下来T行,每行两个正整数,表示

【BZOJ 1854】 [Scoi2010]游戏

1854: [Scoi2010]游戏 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 2609  Solved: 931 [Submit][Status] Description lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备时,他只能使用该装备的某一个属性.并且每种装备最多只能使用一次. 游戏进行到最后,lxhgww遇到了终极boss,这个终极bos

【BZOJ 1036】【ZJOI 2008】树的统计

此题为树链剖分的裸题. 代码如下,使用常用的轻重链剖分. /************************************************************** Problem: 1036 User: Evensgn Language: C++ Result: Accepted Time:2468 ms Memory:5772 kb ****************************************************************/ #inc

【BZOJ 1150】 1150: [CTSC2007]数据备份Backup (贪心+优先队列)

1150: [CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅

【BZOJ 2823】 [AHOI2012]信号塔

2823: [AHOI2012]信号塔 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 469  Solved: 198 [Submit][Status][Discuss] Description 在野外训练中,为了确保每位参加集训的成员安全,实时的掌握和收集周边环境和队员信息非常重要,集训队采用的方式是在训练所在地散布N个小型传感器来收集并传递信息,这些传感器只与设在集训地中的信号塔进行通信,信号塔接收信号的覆盖范围是圆形,可以接收到所有分布在

【BZOJ 3190】 [JLOI2013]赛车

3190: [JLOI2013]赛车 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 803 Solved: 279 [Submit][Status][Discuss] Description 这里有一辆赛车比赛正在进行,赛场上一共有N辆车,分别称为个g1,g2--gn.赛道是一条无限长的直线.最初,gi位于距离起跑线前进ki的位置.比赛开始后,车辆gi将会以vi单位每秒的恒定速度行驶.在这个比赛过程中,如果一辆赛车曾经处于领跑位置的话(即没有其他

【BZOJ 2115】 [Wc2011] Xor

2115: [Wc2011] Xor Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 962  Solved: 441 [Submit][Status] Description Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边. 图中可能有重边或自环. Output 仅包含一个整数,表示最大的XOR和(十进

【BZOJ 1146】 [CTSC2008]网络管理Network

1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MB Submit: 1938  Solved: 577 [Submit][Status] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机