题意:给你一个数组a[n],对于数组每次建立一个完全k叉树,对于每个节点,如果父节点的值比这个节点的值大,那么就是一个违规点,统计出1~n-1完全叉树下的违规点的各自的个数。

一个直觉的思想就是暴力,因为完全k叉树当k很大的时候,其实层数是特别小的,所以感觉暴力是可以的。注意到一个完全k叉树下v节点的儿子的公式是:

k*(v-1)+2...kv+1,相应的父节点的公式是 (v+k-2)/k。儿子的编号是连续的,如果我们可以对每个节点快速的求出连续编号的节点有多少个数比它小我们就可以快速的更新答案了,但是如果对每个节点都这样做的话就至少是一个O(n^2)级别的做法。注意到对于一棵完全k叉树来说,只有内节点才需要统计,叶节点并不需要。而对于一个大小为n的完全k叉树来说,内节点的个数是O(n/k)的,因此总的内节点个数就是n/1+n/2+n/3+...n/n-1,即O(nlogn)。

然后就是单次询问一段连续的区间里有多少个数比v小。这里我没有想到什么好的简便的方法,不过函数式线段树是一个解决方法。root[i]表示的是用a[i]~a[n]的值建立的线段树,当我需要询问某个区间[l,r]的小于等于v的数有多少个数时,只需要query(root[l],1,v)-query(root[r],1,v)即可。空间复杂度是O(nlogn),时间复杂度是单次询问O(logn),最后总的复杂度就是O(nlog^2 n)

#pragma warning(disable:4996)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
using namespace std; #define maxn 200500
#define maxc maxn*20 int n;
int a[maxn], b[maxn];
int res[maxn];
int root[maxn];
int nsize; int lc[maxc], rc[maxc];
int sum[maxc];
int tot; int insert(int rt, int L, int R, int v)
{
int cur = tot++;
if (L == R){
sum[cur] = sum[rt] + 1;
return cur;
}
int M = (L + R) >> 1;
if (v <= M){
rc[cur] = rc[rt];
lc[cur] = insert(lc[rt], L, M, v);
}
else{
lc[cur] = lc[rt];
rc[cur] = insert(rc[rt], M + 1, R, v);
}
sum[cur] = sum[lc[cur]] + sum[rc[cur]];
return cur;
} int query(int rt, int L, int R, int l, int r)
{
if (l == L&&r == R){
return sum[rt];
}
int M = (L + R) >> 1;
if (r <= M){
return query(lc[rt], L, M, l, r);
}
else if (l>M){
return query(rc[rt], M + 1, R, l, r);
}
else{
return query(lc[rt], L, M, l, M) + query(rc[rt], M + 1, R, M + 1, r);
}
} int main()
{
while (cin >> n)
{
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
b[i] = a[i];
}
sort(b+1, b + n+1);
nsize = unique(b+1, b + n+1) - b;
for (int i = 1; i <= n; ++i){
a[i] = lower_bound(b + 1, b + nsize, a[i]) - b + 1;
}
memset(res, 0, sizeof(res));
tot = 1;
root[n + 1] = tot;
lc[tot] = rc[tot] = sum[tot] = 0;
tot++;
for (int i = n; i >= 1; i--){
root[i] = insert(root[i + 1], 1, nsize, a[i]);
}
for (int k = 1; k <= n - 1; ++k){
int maxBound = (n + k - 2) / k;
for (int v = 1; v <= maxBound; ++v){
int cnt = 0;
int lbound = k*(v - 1) + 2;
int rbound = min(k*v + 1, n);
cnt = query(root[lbound], 1, nsize, 1, a[v] - 1)- query(root[rbound+1], 1, nsize, 1, a[v] - 1);
res[k] += cnt;
}
}
for (int i = 1; i <= n - 1; ++i){
if (i > 1) printf(" ");
printf("%d", res[i]);
}
puts("");
}
return 0;
}

Codeforces538F A Heap of Heaps(函数式线段树)的更多相关文章

  1. [codeforces538F]A Heap of Heaps

    [codeforces538F]A Heap of Heaps 试题描述 Andrew skipped lessons on the subject 'Algorithms and Data Stru ...

  2. 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))

    函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...

  3. POJ2104 K-th number 函数式线段树

    很久没打代码了,不知道为什么,昨天考岭南文化之前突然开始思考起这个问题来,这个问题据说有很多种方法,划分树什么的,不过对于我现在这种水平还是用熟悉的线段树做比较好.这到题今年8月份的时候曾经做过,那个 ...

  4. BZOJ 3123 森林(函数式线段树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3123 题意: 思路:总的来说,查询区间第K小利用函数式线段树的减法操作.对于两棵树的合并 ...

  5. BZOJ 3207 花神的嘲讽计划Ⅰ(函数式线段树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3207 题意:给出一个数列,若干询问.每个询问查询[L,R]区间内是否存在某个长度为K的子 ...

  6. [Usaco2014 Open Gold ]Cow Optics (树状数组+扫描线/函数式线段树)

    这道题一上手就知道怎么做了= = 直接求出原光路和从目标点出发的光路,求这些光路的交点就行了 然后用树状数组+扫描线或函数式线段树就能过了= = 大量的离散+模拟+二分什么的特别恶心,考试的时候是想到 ...

  7. hdu 5111 树链剖分加函数式线段树

    这题说的是给了两棵树,各有100000 个节点,然后Q个操作Q<=50000; 每个操作L1 R1 L2 R2.因为对于每棵树都有一个与本棵树其他点与众不同的值, 最后问 在树上从L1到R1这条 ...

  8. BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec   Memory Limit: 512 MB Submit: 418   Solved: 235 [ Submit][ ...

  9. 【bzoj3065】: 带插入区间K小值 详解——替罪羊套函数式线段树

    不得不说,做过最爽的树套树———— 由于有了区间操作,我们很容易把区间看成一棵平衡树,对他进行插入,那么外面一层就是平衡树了,这就与我们之前所见到的不同了.我们之前所见到的大多数是线段树套平衡树而此题 ...

随机推荐

  1. OpenCV学习笔记(十一) 轮廓操作

    在图像中寻找轮廓 首先利用Canny算子检测图像的边缘,再利用Canny算子的输出作为 寻找轮廓函数 findContours 的输入.最后用函数 drawContours 画出轮廓.边界Counto ...

  2. 7 Vue.js实现loading1

    1 2 3 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter ...

  3. anr trace文件分析

    测试给的trace文件好几万行,怎么看? 1.搜索 你的包名,看它报错误报在你代码的哪里 2.在你代码里面分析 还有,synchronized 就是用来防止多线程调用的,没有那么神奇.

  4. elasticsearch索引和映射

    目录 1. elasticsearch如何实现搜索 1.1 搜索实例 1.2 es中数据的类型 1.3 倒排索引 1.4 分析与分析器 1.4.1 什么是分析器 1.4.2 内置分析器种类 1.4.3 ...

  5. Server Message Block

    Question: Server Message Block文件共享存储虚拟机的优势是什么? Answer:微软在Windows Server 2012和Hyper-V 3.0中引进了SMB文件共享存 ...

  6. erlang连接mysql [转]

    转自: http://blog.csdn.net/flyinmind/article/details/7740540 项目中用到erlang,同时也用到mysql.惯例,google. 但是,按照网上 ...

  7. CSS3 3D圆形设计教程

    http://www.htmleaf.com/ziliaoku/qianduanjiaocheng/201502061338.html

  8. 【APUE】Chapter8 Process Control

    这章的内容比较多.按照小节序号来组织笔记的结构:再结合函数的示例带代码标注出来需要注意的地方. 下面的内容只是个人看书时思考内容的总结,并不能代替看书(毕竟APUE是一本大多数人公认的UNIX圣经). ...

  9. 【Pascal's Triangle】cpp

    题目: Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,R ...

  10. leetcode 【 Linked List Cycle 】 python 实现

    题目: Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ...