【题目描述】

【输入格式】

【输出格式】

S
a
m
p
l
e
I
n
p
u
t
Sample~~Input
Sample Input
5 5
1 2 3 4 5
Q 1 3 2
Q 1 3 1
C 2 1
Q 1 3 2
Q 1 3 1
S a m p l e O u t p u t Sample~~Output Sample Output
1
1
0
2
【题意分析】
上来就是非常 n a i v e naive naive的分块,但是有两个问题亟待解决:
1、内存,
n
n
n\sqrt n
nn的int显然会挂,但我们可以用short,卡着线就过去了
2、关于离散化,用map离散的话亲测只有10pts,比暴力还低30分,足以证明频繁调用map带来的复杂度之大。这个怎么解决呢?浅色调julao的第二个分块做法给出了指针模拟map的做法,具体就是:一个指针类型数组保存所有读入和输出中的颜色种类(原本有2147483647种),指向这些数据本身,排序之后线扫一遍并标号。由于指针地址的缘故,重新标号的同时也完成了离散化。注意sort的cmp函数记得采用*int类型比较
离散化的具体操作看代码,其实不用火车头也稳稳能过,每个点比map接近快了10000ms
Code:
#pragma GCC diagnostic error "-std=c++11"
#pragma GCC target("avx")
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <map>
#include <algorithm>
#define MAXN 200005
using namespace std;
struct Node {
int a, b, c, opt;
}ques[MAXN];
short sum[318][MAXN];
int belong[MAXN], a[MAXN], l[MAXN], r[MAXN], *b[MAXN], n, m, block, num, tot;
inline int read () {
register int s = 0, w = 1;
register char ch = getchar ();
while (! isdigit (ch)) {if (ch == '-') w = -1; ch = getchar ();}
while (isdigit (ch)) {s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar ();}
return s * w;
}
inline bool cmp (int *a, int *b) {return *a < *b;}
inline void query (int L, int R, int k) {
int ans = 0;
if (belong[R] - belong[L] <= 1) {
for (register int i = L; i <= R; i++)
ans += (a[i] == k);
printf ("%d\n", ans); return;
}
for (register int i = L; i <= r[belong[L]]; i++) ans += (a[i] == k);
for (register int i = l[belong[R]]; i <= R; i++) ans += (a[i] == k);
for (register int i = belong[L] + 1; i <= belong[R] - 1; i++) ans += sum[i][k];
printf ("%d\n", ans);
}
inline void modify (int x, int y) {
sum[belong[x]][a[x]]--;
sum[belong[x]][y]++;
a[x] = y;
}
int main () {
n = read (), m = read (), block = floor (sqrt (n));
if (n % block == 0) num = n / block; else num = n / block + 1;
for (register int i = 1; i <= n; i++)
a[i] = read (), b[++tot] = &a[i], belong[i] = i / block + (i % block == 0) ? 0 : 1;
for (register int i = 1; i <= num; i++)
l[i] = (i - 1) * block + 1, r[i] = min (n, i * block);
for (register int i = 1; i <= m; i++) {
char opt[5]; scanf ("%s", opt);
ques[i].a = read (), ques[i].b = read ();
if (opt[0] == 'Q') ques[i].opt = 1, ques[i].c = read (), b[++tot] = &ques[i].c;
else b[++tot] = &ques[i].b;
}
sort (b + 1, b + tot + 1, cmp); int cnt = 0, lst = -1;
for (register int i = 1; i <= tot; i++) {
if (*b[i] != lst) lst = *b[i], cnt++;
*b[i] = cnt;
}
for (register int i = 1; i <= n; i++) sum[belong[i]][a[i]]++;
for (register int i = 1; i <= m; i++) {
if (ques[i].opt == 1) query (ques[i].a, ques[i].b, ques[i].c);
else modify (ques[i].a, ques[i].b);
}
return 0;
}
离散化与分块技术在SDOI2008题目的应用解析

这篇博客主要分析了SDOI2008题目中遇到的离散化和内存优化问题。通过使用short类型节省内存,并提出了一种基于指针模拟map的离散化方法,解决了频繁调用map导致的时间复杂度问题。博主详细介绍了指针数组排序和标号的过程,指出这种方法比直接使用map快了10000ms,对于理解离散化和分块技术在算法中的应用提供了实用的思路。

被折叠的 条评论
为什么被折叠?



