[BZOJ 3236] [Ahoi2013] 作业 && [BZOJ 3809] 【莫队 | 分块】

题目链接: BZOJ - 3236   BZOJ - 3809

算法一:莫队

首先,单纯的莫队算法是很好想的,就是用普通的第一关键字为 l 所在块,第二关键字为 r 的莫队。

这样每次端点移动添加或删除一个数字,用树状数组维护所求的信息就是很容易的。由于这里有 logn复杂度,所以复杂度还是挺高的。

于是 BZOJ-3236 的时限 100s,我的代码跑了 98s,险过......

However..BZOJ-3809 的出题人(SLYZ的神犇)就没有这么善良了!直接内存限制 28MB 就直接把我的莫队卡成 MLE!这是处心积虑卡莫队的恶劣行为!严正抗议!

Paste一个BZOJ-3236的纯莫队代码:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

inline void Read(int &Num) {
	char c; c = getchar();
	while (c < ‘0‘ || c > ‘9‘) c = getchar();
	Num = c - ‘0‘; c = getchar();
	while (c >= ‘0‘ && c <= ‘9‘) {
		Num = Num * 10 + c - ‘0‘;
		c = getchar();
	}
}

const int MaxN = 100000 + 5, MaxM = 1000000 + 5;

int n, m, BlkSize;
int A[MaxN], Cnt[MaxN], T1[MaxN], T2[MaxN];

struct Query
{
	int l, r, a, b, Pos, e, Ans1, Ans2;
	Query() {}
	Query(int x, int y, int p, int q, int o) {
		l = x; r = y; a = p; b = q; Pos = o;
	}
	bool operator < (const Query &q) const {
		if (e == q.e) return r < q.r;
		return e < q.e;
	}
} Q[MaxM];

inline bool Cmp(Query q1, Query q2) {
	return q1.Pos < q2.Pos;
}

inline void Add1(int x, int Num) {
	for (int i = x; i <= n; i += i & -i)
		T1[i] += Num;
}
inline int Get1(int x) {
	if (x == 0) return 0; //Notice!
	int ret = 0;
	for (int i = x; i; i -= i & -i)
		ret += T1[i];
	return ret;
}

inline void Add2(int x, int Num) {
	for (int i = x; i <= n; i += i & -i)
		T2[i] += Num;
}
inline int Get2(int x) {
	if (x == 0) return 0; //Notice!
	int ret = 0;
	for (int i = x; i; i -= i & -i)
		ret += T2[i];
	return ret;
}

inline void Add_Num(int x) {
	if (Cnt[x] == 0) Add2(x, 1);
	++Cnt[x];
	Add1(x, 1);
}
inline void Del_Num(int x) {
	--Cnt[x];
	Add1(x, -1);
	if (Cnt[x] == 0) Add2(x, -1);
}

void Pull(int f, int x, int y) {
	if (x == y) return;
	if (f == 0)
		if (x < y)
			for (int i = x; i < y; ++i) Del_Num(A[i]);
		else
			for (int i = x - 1; i >= y; --i) Add_Num(A[i]);
	else
		if (x < y)
			for (int i = x + 1; i <= y; ++i) Add_Num(A[i]);
		else
			for (int i = x; i > y; --i) Del_Num(A[i]);
}

int main()
{
	Read(n); Read(m);
	BlkSize = (int)sqrt((double)n);
	for (int i = 1; i <= n; ++i) Read(A[i]);
	int l, r, a, b;
	for (int i = 1; i <= m; ++i) {
		Read(l); Read(r); Read(a); Read(b);
		Q[i] = Query(l, r, a, b, i);
		Q[i].e = (l - 1) / BlkSize + 1;
	}
	sort(Q + 1, Q + m + 1);
	memset(Cnt, 0, sizeof(Cnt));
	memset(T1, 0, sizeof(T1));
	memset(T2, 0, sizeof(T2));
	for (int i = Q[1].l; i <= Q[1].r; ++i) Add_Num(A[i]);
	Q[1].Ans1 = Get1(Q[1].b) - Get1(Q[1].a - 1);
	Q[1].Ans2 = Get2(Q[1].b) - Get2(Q[1].a - 1);
	for (int i = 2; i <= m; ++i) {
		if (Q[i].r < Q[i - 1].l) {
			Pull(0, Q[i - 1].l, Q[i].l);
			Pull(1, Q[i - 1].r, Q[i].r);
		}
		else {
			Pull(1, Q[i - 1].r, Q[i].r);
			Pull(0, Q[i - 1].l, Q[i].l);
		}
		Q[i].Ans1 = Get1(Q[i].b) - Get1(Q[i].a - 1);
		Q[i].Ans2 = Get2(Q[i].b) - Get2(Q[i].a - 1);
	}
	sort(Q + 1, Q + m + 1, Cmp);
	for (int i = 1; i <= m; ++i) printf("%d %d\n", Q[i].Ans1, Q[i].Ans2);
	return 0;
}

算法二:

时间: 2024-09-20 00:52:56

[BZOJ 3236] [Ahoi2013] 作业 && [BZOJ 3809] 【莫队 | 分块】的相关文章

BZOJ 3236: [Ahoi2013]作业( 莫队 + BIT )

莫队..用两个树状数组计算.时间复杂度应该是O(N1.5logN). 估计我是写残了...跑得很慢... ------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x) & -(x)) const int maxn = 100009; const int maxm =

bzoj 3236: [Ahoi2013]作业(缺线段树)

3236: [Ahoi2013]作业 Time Limit: 100 Sec  Memory Limit: 512 MBSubmit: 1744  Solved: 702[Submit][Status][Discuss] Description Input Output Sample Input 3 4 1 2 2 1 2 1 3 1 2 1 1 1 3 1 3 2 3 2 3 Sample Output 2 2 1 1 3 2 2 1 HINT N=100000,M=1000000 Sourc

BZOJ 3236: [Ahoi2013]作业

题目 3236: [Ahoi2013]作业 Time Limit: 100 Sec  Memory Limit: 512 MBSubmit: 732  Solved: 271 Description Input Output Sample Input 3 4 1 2 2 1 2 1 3 1 2 1 1 1 3 1 3 2 3 2 3 Sample Output 2 2 1 1 3 2 2 1 HINT N=100000,M=1000000 Source By wangyisong1996加强数据

Bzoj 3781: 小B的询问 莫队,分块,暴力

3781: 小B的询问 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 426  Solved: 284[Submit][Status][Discuss] Description 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. Input 第一行,三个整数N.M.K. 第二行

树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Outpu

AC日记——[Ahoi2013]作业 bzoj 3236

3236 思路: 莫队+树状数组维护: 代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 100005 struct QueryType { int l,r,a,b,id; }; struct QueryType qu[maxn*10

莫队+分块 BZOJ 3809

3809: Gty的二逼妹子序列 Time Limit: 80 Sec  Memory Limit: 28 MBSubmit: 1634  Solved: 482[Submit][Status][Discuss] Description Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题. 对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数. 为了方便,我们规定妹子们的美丽度全都在[1,n]中. 给定一个长度为n(1<=n<=100000)

[BZOJ 3585] mex 【莫队+分块】

题目链接:BZOJ - 3585 题目分析 区间mex,即区间中没有出现的最小自然数. 那么我们使用一种莫队+分块的做法,使用莫队维护当前区间的每个数字的出现次数. 然后求mex用分块,将权值分块(显然mex 一定小于等于 n ,大于 n 的权值没有意义,可以直接忽略),每块大小 sqrt(n) . 然后区间中的某个数的数量被减到0的时候就将它所在的块的种类计数减一,添加数的时候类似. 然后枚举每个块,找到最小的中间有数不存在的块(即种类数小于块中的数的种数),然后到这个快里直接从小一个一个找到

BZOJ 4129 Haruna’s Breakfast 带修改树上莫队+分块

题目大意:给定一棵树,每个点有一个非负点权,支持下列操作 1.修改某个点的点权 2.查询某条链上的mex 考虑链上不带修改的版本,我们可以用莫队+分块来搞(链接戳这里) 现在到了树上带修改,果断糖果公园 本来抱着逗比的心态写了一发结果1.4s过了 跟糖果公园的80s完全不成正比啊0.0 #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <