题目链接:XJOI NOI2015-13 A

题目分析

首先,题目定义的这种矩阵有一个神奇的性质,第 4 行与第 2 行相同,于是第 5 行也就与第 3 行相同,后面的也是一样。

因此矩阵可以看做只有 3 行,从上到下就是 1 2 3 2 3 2 3 ......

然后我们使用分块,将每一行分成 sqrt(m) 大小的块。

然后维护 A[i][j] —— 第一行前 i 块中,数字 j 的出现次数。

同时维护 B[i][j] —— 第二行前 i 块中,数字 j 的出现次数。

这里要将第一行的数字进行离散化减小 j 的范围。(同时要注意,询问第一行的数字时,不要直接输出了离散化之后的数字QAQ,要输出原本的数字,我就是这么WA的)

然后对于询问第二行的 x 位置,就先加上第一行 [1, x] 中前面的整个 k 块中这个数字的个数,再 O(sqrt n) 枚举最后一个块中前面到 x 的一段。

对于询问第三行的 x 位置,先计算第二行 x 位置的数值 Num ,加上第二行 [1, x] 中前面的整个 k 块中的 Num 个数,后面再求出最后一个块中前面到 x 的一段中有几个 Num,注意这里不能每个位置都 O(sqrt n) 求,而是 O(sqrt n) 扫一遍,同时用一个 Cnt[MaxNum] 的数组将扫到的数字对应的累加器+1,这样扫到一个位置就可以立即算出第二行这个位置的值了,最后再扫一遍将累加器减回去。

对于修改第一行的某个位置,显然可以向后扫每个块然后更新一下 A[][] 数组,然而 B[][] 的维护其实也是可以枚举后面的每个块然后总体 O(sqrt n) 维护的。

将修改操作分为插入和删除操作就可以很清晰地维护了。

代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map> using namespace std; inline int gmax(int a, int b) {return a > b ? a : b;} inline void Read(int &Num)
{
char 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();
}
} map<int, int> M; const int MaxN = 100000 + 5, MaxNum = 200000 + 5, MaxB = 150 + 5; int n, m, k, Index, Blk, Tot;
int A[MaxN], T[MaxN], Belong[MaxN], L[MaxB], R[MaxB], Sum[MaxB][MaxNum][2], Cnt[MaxNum]; int Query2(int x)
{
int ret = Sum[Belong[x] - 1][A[x]][0];
for (int i = L[Belong[x]]; i <= x; ++i)
if (A[i] == A[x]) ++ret;
return ret;
} int Query3(int x)
{
int Now, Num, ret;
Num = Query2(x);
ret = Sum[Belong[x] - 1][Num][1];
for (int i = L[Belong[x]]; i <= x; ++i)
{
++Cnt[A[i]];
Now = Sum[Belong[x] - 1][A[i]][0] + Cnt[A[i]];
if (Now == Num) ++ret;
}
for (int i = L[Belong[x]]; i <= x; ++i)
--Cnt[A[i]];
return ret;
} int main()
{
scanf("%d%d%d", &n, &m, &k);
Index = 0;
int Num;
for (int i = 1; i <= m; ++i)
{
Read(Num);
if (M[Num] == 0) M[Num] = ++Index;
A[i] = M[Num];
T[i] = Num;
}
Blk = gmax((int)sqrt((double)m), m / 150);
for (int i = 1; i <= m; ++i)
{
Belong[i] = (i - 1) / Blk + 1;
if (L[Belong[i]] == 0) L[Belong[i]] = i;
R[Belong[i]] = i;
}
Tot = Belong[m];
for (int i = 1; i <= m; ++i)
for (int j = Belong[i]; j <= Tot; ++j)
++Sum[j][A[i]][0];
for (int i = 1; i <= m; ++i)
{
Num = Query2(i);
for (int j = Belong[i]; j <= Tot; ++j)
++Sum[j][Num][1];
}
int t, x, y, Ans;
for (int i = 1; i <= k; ++i)
{
Read(t); Read(x); Read(y);
if (t == 0)
{
if (x == 1) Ans = T[y];
else if (x & 1) Ans = Query3(y);
else Ans = Query2(y);
printf("%d\n", Ans);
}
else
{
T[x] = y;
if (M[y] == 0) M[y] = ++Index;
y = M[y];
for (int j = Belong[x]; j <= Tot; ++j)
--Sum[j][Sum[j][A[x]][0]][1];
for (int j = Belong[x]; j <= Tot; ++j)
--Sum[j][A[x]][0];
A[x] = y;
for (int j = Belong[x]; j <= Tot; ++j)
++Sum[j][A[x]][0];
for (int j = Belong[x]; j <= Tot; ++j)
++Sum[j][Sum[j][A[x]][0]][1];
}
}
return 0;
}

  

[XJOI NOI2015模拟题13] A 神奇的矩阵 【分块】的更多相关文章

  1. [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】

    题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动 ...

  2. [XJOI NOI2015模拟题13] B 最小公倍数 【找规律】

    题目链接:XJOI - NOI2015-13 - B 题目分析 通过神奇的观察+打表+猜测,有以下规律和性质: 1) 删除的 n 个数就是 1~n. 2) 当 c = 2 时,如果 n + 1 是偶数 ...

  3. XJOI NOIP模拟题2

    第一题 组合计数 分析: 从前往后一位一位的计算 先算第一位比t小的数目,再算第一位与t[1]相同,第2位比t小的个数以此类推 先预处理一个数组h,h[i]表示从1~it串与s串不同的位数 对于第i位 ...

  4. XJOI NOIP模拟题1

    第一题 分析: 开始想的是贪心,取每列均值最大一段. 应该是01分数规划,具体看代码 代码: program gold; var a:..]of int64; n,i,m,j,x:longint; f ...

  5. 【做题】HDU6331 Walking Plan——矩阵&分块

    题意:给出一个有\(n\)个结点的有向图,边有边权.有\(q\)组询问,每次给出\(s,t,k\),问从\(s\)到\(t\)至少经过\(k\)条边的最短路. \(n \leq 50, \, q \l ...

  6. 神奇的矩阵 NOI模拟题

    神奇的矩阵 题目大意 有一个矩阵\(A\),第一行是给出的,接下来第\(x\)行,第\(y\)个元素的值为数字\(A_{x-1,y}\)在\(\{A_{x-1,1},A_{x-1,2},A_{x-1, ...

  7. poj 1008:Maya Calendar(模拟题,玛雅日历转换)

    Maya Calendar Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 64795   Accepted: 19978 D ...

  8. poj 1888 Crossword Answers 模拟题

    Crossword Answers Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 869   Accepted: 405 D ...

  9. ZOJ1111:Poker Hands(模拟题)

    A poker deck contains 52 cards - each card has a suit which is one of clubs, diamonds, hearts, or sp ...

随机推荐

  1. centos 7访问windows共享文件夹

    1. 首先centos要能识别win7的文件系统ntfs,原版的centos是不支持NTFS格式的文件系统,因此需要安装ntfs支持软件包,我使用的是rpmforge软件库,在此处http://pkg ...

  2. js动态生成按钮,页面用DIV简单布局2

    对前边不完善的修改 <!DOCTYPE html><html><head><title>test.html</title> <meta ...

  3. js如何实现一定时间后去执行一个函数

    js如何实现一定时间后去执行一个函数:在实际需要中可能需要规定在指定的时间之后再去执行一个函数以达成期望的目的,这也就是一个定时器效果,恰好在js中就已经给定了这样的一个函数setTimeout(), ...

  4. sharepoint 删除list里的所有内容

    [System.reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") $siteUrl = " ...

  5. 如何让Div层悬浮在Flash Object对象之上(转载)

    今天有个用户,门户右上角的倒三角登陆小按钮在他的电脑上无法显示,他用的笔记本屏幕较小,宽度正好显示出页面内容,经查看,门户页眉使用的为flash对象. 大家都知道,如果想让某个图片或者Div层悬浮在别 ...

  6. 使用 vmstat 监测系统性能

    在linux/unix下,vmstat是常用的系统性能监测工具.常用用法如下 vmstat 1 10 表示以1秒为间隔,做相关参数的采样,一共10次.输出范例如下: procs ----------- ...

  7. .Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法

    阐述签名工具这个概念之前,我先说说它不是什么: 1.它不是用于给程序集加密的工具,它与阻止Reflector或ILSpy对程序集进行反编译一毛钱关系都没有. 2.它很讨厌人们把它和加密联系在一起. 我 ...

  8. mac安装软件运行提示「xxx.app已损坏,打不开.你应该将它移到废纸篓」的解决办法

    「xxx.app已损坏,打不开.你应该将它移到废纸篓」,其实并非你安装的软件已损坏,而是Mac系统的安全设置问题,往往这些软件可能是经过了汉化或者破解,所以被Mac认为「已损坏」,那么解决方法就是临时 ...

  9. [LCA & RMQ] [NOIP2013] 货车运输

    首先看到这题, 由于要最大, 肯定是求最大生成树 那么 o(n2) dfs 求任意点对之间的最小边是可以想到的 但是看看数据范围肯定TLE 于是暴力出来咯, 不过要注意query的时候判断的时候要 m ...

  10. 霍纳法则(Horner's rule)

    卡在hdu 1402 的高精度乘法了,要用FFT(快速傅里叶变换),然后看到了这个霍纳法则,顺便就写下来了. 霍纳法则:求多项式值的一个快速算法. 简单介绍: 假设有n+2个数 , a0,a1,a2, ...