【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坐标递增的顺序,也不需要先处理出左边的信息才能更新右边的信息。

这样直接整体二分啊~~~~~处理完一大块左边对右边的贡献再递归处理左右两块。只要一开始对x坐标排序即可,solve的过程从整到散,不需要再进行排序。

一开始还忘了离散化,每次清空树状数组都用memsetヽ(*´Д`*)?后来发现从前往后扫一遍把原先加的减回去会快得多。

时间复杂度$O(mlogmlogw)$,m的含义为所有修改和询问的数量,w的含义为离散化y坐标后的y坐标最大值,即树状数组的上界。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&(-x))
using namespace std;
int in() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < ‘0‘ || c > ‘9‘; c = getchar())
		if (c == ‘-‘) fh = -1;
	for(; c >= ‘0‘ && c <= ‘9‘; c = getchar())
		k = (k << 3) + (k << 1) + c - ‘0‘;
	return k * fh;
}

struct node {
	int op, x, y, a, id, pos;
	bool operator < (const node &A) const {
		return x == A.x ? (y == A.y ? pos < A.pos : y < A.y) : x < A.x;
	}
} Q[200003], q[200003];

int s, w, m = 0, ans[40003];

namespace CDQ {
	int bits[180003];
	void update(int x, int num) {
		for(; x <= w; x += lowbit(x)) bits[x] += num;
	}
	int Qsum(int x) {
		int ret = 0;
		for(; x; x -= lowbit(x)) ret += bits[x];
		return ret;
	}

	void solve(int l, int r) {
		if (l == r) return;
		int mid = (l + r) >> 1;
		for(int i = l; i <= r; ++i) {
			if (Q[i].op == 1 && Q[i].id <= mid) update(Q[i].y, Q[i].a);
			if (Q[i].op == 2 && Q[i].id > mid) ans[Q[i].pos] += Q[i].a * Qsum(Q[i].y);
		}

		for(int i = l; i <= r; ++i)
			if (Q[i].op == 1 && Q[i].id <= mid) update(Q[i].y, -Q[i].a);

		int tl = l, tr = mid + 1;
		for(int i = l; i <= r; ++i)
			if (Q[i].id <= mid) q[tl++] = Q[i];
			else q[tr++] = Q[i];
		for(int i = l; i <= r; ++i) Q[i] = q[i];

		solve(l, mid);
		solve(mid + 1, r);
	}
}

int H[180003], cnt = 0, anscnt = 0;
int main() {
	s = in(); w = in(); int x1, y1, x2, y2;
	for(int x = in(); x != 3; x = in())
		if (x == 1) {
			Q[++m].op = 1;
			Q[m].x = in(); Q[m].y = in(); Q[m].a = in(); Q[m].id = m; Q[m].pos = 0;
			H[++cnt] = Q[m].y;
		} else {
			x1 = in(); y1 = in(); x2 = in(); y2 = in();
			H[++cnt] = y1 - 1; H[++cnt] = y2;
			ans[++anscnt] = s * (x2 - x1 + 1) * (y2 - y1 + 1);
			++m; Q[m] = (node) {2, x1 - 1, y1 - 1, 1, m, anscnt};
			++m; Q[m] = (node) {2, x1 - 1, y2, -1, m, anscnt};
			++m; Q[m] = (node) {2, x2, y1 - 1, -1, m, anscnt};
			++m; Q[m] = (node) {2, x2, y2, 1, m, anscnt};
		}

	sort(H + 1, H + cnt + 1);
	cnt = unique(H + 1, H + cnt + 1) - H;
	w = cnt - 1;

	for(int i = 1; i <= m; ++i)	Q[i].y = lower_bound(H + 1, H + cnt, Q[i].y) - H;

	sort(Q + 1, Q + m + 1);

	CDQ::solve(1, m);

	for(int i = 1; i <= anscnt; ++i) printf("%d\n", ans[i]);

	return 0;
}

一定要想好了再码!

时间: 2025-01-06 18:34:00

【BZOJ 1176】【Balkan 2007】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为矩阵大小 接下来每行为一下

【BZOJ 1176 2683】Mokia

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

【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】3319: 黑白树

http://www.lydsy.com/JudgeOnline/problem.php?id=3319 题意:给一棵n节点的树(n<=1e6),m个操作(m<=1e6),每次操作有两种:1.查询u到根的第一条黑边的编号.2.将u到v的路径全部染成黑色 #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream>

P2433 - 【BZOJ 3262三维偏序】陌上花开------三维偏序

P2433 - [BZOJ 3262三维偏序]陌上花开 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量. 定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,

【bzoj】4538: [Hnoi2016]网络

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4538 维护一个数据结构支持对于一颗树的操作,需要支持: 1.对于树上的一条路径上的每个点上放一个值. 2.撤销某次操作的路劲放. 3.查询除了经过这个点的路径的最大值. 往一个路径上丢值相当于往不经过条路径的所有点上丢值. 用一个树链剖分即可维护,对于操作区间取反. 直接查询单点最大值即可. 为了维护单点最大值,线段树中的每一个点对应两个堆,用于维护插入誉删除. 防止爆空间,所以标记永久

【BZOJ】1821: [JSOI2010]Group 部落划分 Group(最小生成树+贪心)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=1821 这题裸题. 本题要求最短距离最长,很明显,我们排序. 这里存在贪心,即我们把边权最小的全分给n个部落的内部,然后剩下的边最小的就是答案. 将边权较小的边分给k个部落,用并查集生成最小树,使得内部的边总是小于连到外部的边.然后分剩下k个点即可,剩下的k个点的那条边一定是部落之间最小的且最长的边. #include <cstdio> #include <cstring> #

【BZOJ】【3083】遥远的国度

树链剖分/dfs序 其实过了[BZOJ][4034][HAOI2015]T2以后就好搞了…… 链修改+子树查询+换根 其实静态树的换根直接树链剖分就可以搞了…… 因为其实只有一样变了:子树 如果root在x的子树中(以1为根dfs的时候),那么现在x的子树就变成了整个dfs序中,除去含有root的那个子树的剩下的部分,画个图大概就是这样:(红色部分为现在的子树) 我们发现,这种子树由于换根而产生变化的情况,仅当在以1为根时的树中,x是new_root的祖先时发生,那么我们判断这种情况是否发生只需

【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