UVA 11990 `Dynamic'' Inversion CDQ分治, 归并排序, 树状数组, 尺取法, 三偏序统计 难度: 2
题目
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3141
题意
一个1到n的排列,每次随机删除一个,问删除前的逆序数
思路
综合考虑,对每个数点,令value为值,pos为位置,time为出现时间(总时间-消失时间),明显是统计value1 > value2, pos1 < pos2, time1 < time2的个数
首先对其中一个轴排序,比如value,这样在归并过程中,左子树的value总是小于右子树的,可以分治。
当左右子树包含哪些数点已经确定后,可以用自下而上的归并排序使得子树上的数点按照第二维相对有序,方便用尺取法统计子树之间的逆序数。
第三维通过树状数组进行压缩,加快统计速度。
注意仅仅统计左子树对右子树的影响,就会错过右子树中的数点出现的比较晚的情况。因此需要统计右子树对左子树的影响,此时注意别把同一时间出现的重复计数。
感想
1. 注意long long!!!
2. BIT的上限要>=n!
3. 注意统计影响完成后需要清空树状数组(区间大小已经减少了所以可以浪费地使用),此时不能直接用memset清空整个数组,时间会成为O(n2),超时。
代码
时间: 0.250s
时间复杂度O(cnlogn)
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <queue>
#include <tuple>
#include <cassert> using namespace std; const int MAXN = int(4e5 + ); #define LEFT_CHILD(x) ((x) << 1)
#define RIGHT_CHILD(x) (((x) << 1) + 1)
#define FATHER(x) ((x) >> 1)
#define IS_LEFT_CHILD(x) (((x) & 1) == 0)
#define IS_RIGHT_CHILD(x) (((x) & 1) == 1)
#define BROTHER(x) ((x) ^ 1)
#define LOWBIT(x) ((x) & (-x)) #define LOCAL_DEBUG struct Node{
int value, pos, time;
}nodes[MAXN], tmpNodes[MAXN]; int timeCnt[MAXN * ];
long long revNum[MAXN];
int clearStack[MAXN];
int clearLen;
int n, m;
int bitLimit; int getHigherBit(int n) {
int x = ;
while (x < n) { x <<= ; }
return x;
} void update(int id) {
while (id <= bitLimit) {
if (timeCnt[id] == ) {
clearStack[clearLen++] = id;
}
timeCnt[id]++;
id += LOWBIT(id);
}
} void clearCnt() {
while (clearLen > ) {
timeCnt[clearStack[--clearLen]] = ;
}
} int countTimesSmaller(int id) {
if (id < )return ;
int sum = ;
int tmp = ;
while (id > ) {
sum += timeCnt[id];
id -= LOWBIT(id);
}
return sum;
} void merge_by_pos(int root_ind, int internal_l, int internal_r) {
int internal_mid = (internal_l + internal_r) >> ;
for (int i = internal_l; i <= internal_r; i++) {
tmpNodes[i] = nodes[i];
}
for (int i = internal_l, j = internal_mid + , ind = internal_l; ind <= internal_r; ) {
if (i > internal_mid) {
nodes[ind++] = tmpNodes[j++];
}
else if (j > internal_r) {
nodes[ind++] = tmpNodes[i++];
}
else if (tmpNodes[i].pos < tmpNodes[j].pos) {
nodes[ind++] = tmpNodes[i++];
}
else {
nodes[ind++] = tmpNodes[j++];
}
}
}
void cal(int root_ind, int internal_l, int internal_r) {
if (internal_l == internal_r)return;
int internal_mid = (internal_l + internal_r) >> ;
if(internal_l != internal_mid)cal(LEFT_CHILD(root_ind), internal_l, internal_mid);
if (internal_mid + != internal_r)cal(RIGHT_CHILD(root_ind), internal_mid + , internal_r);
// printf("L Node: %d[%d, %d] LC: %d[%d, %d], RC: %d[%d, %d]\n", root_ind, internal_l, internal_r, LEFT_CHILD(root_ind), internal_l, internal_mid, RIGHT_CHILD(root_ind), internal_mid + 1, internal_r);
for (int i = internal_l, j = internal_mid + ; i <= internal_mid; i++) {
while (j <= internal_r && nodes[i].pos > nodes[j].pos) {
update(nodes[j].time);
j++;
}
revNum[nodes[i].time] += countTimesSmaller(nodes[i].time);
// printf("L (%d, %d, %d): +%d\n", nodes[i].value, nodes[i].pos, nodes[i].time, countTimesSmaller(nodes[i].time));
}
clearCnt(); for (int i = internal_mid, j = internal_r; j > internal_mid; j--) {
while (i >= internal_l && nodes[i].pos > nodes[j].pos) {
update(nodes[i].time);
i--;
}
revNum[nodes[j].time] += countTimesSmaller(nodes[j].time - );
// printf("R (%d, %d, %d): +%d\n", nodes[j].value, nodes[j].pos, nodes[j].time, countTimesSmaller(nodes[j].time - 1));
}
clearCnt();
merge_by_pos(root_ind, internal_l, internal_r); } int main() {
#ifdef LOCAL_DEBUG
freopen("input.txt", "r", stdin);
freopen("output2.txt", "w", stdout);
#endif // LOCAL_DEBUG
for (int ti = ; scanf("%d%d", &n, &m) == ; ti++) {
bitLimit = getHigherBit(n);
for (int i = ; i <= n; i++) {
int tmp;
scanf("%d", &tmp);
nodes[tmp].value = tmp;
nodes[tmp].pos = i;
nodes[tmp].time = ;
}
for (int i = ; i <= m + ; i++) { revNum[i] = ; }
for (int i = ; i < m; i++) {
int tmp;
scanf("%d", &tmp);
nodes[tmp].time = m - i + ;
}
cal(, , n);
long long ans = ;
for (int i = ; i <= m + ; i++) { ans += revNum[i]; }
for (int i = ; i < m; i++) {
printf("%lld\n", ans);
ans -= revNum[m - i + ];
}
}
return ;
}
UVA 11990 `Dynamic'' Inversion CDQ分治, 归并排序, 树状数组, 尺取法, 三偏序统计 难度: 2的更多相关文章
- [APIO2019] [LOJ 3146] 路灯 (cdq分治或树状数组套线段树)
[APIO2019] [LOJ 3146] 路灯 (cdq分治或树状数组套线段树) 题面 略 分析 首先把一组询问(x,y)看成二维平面上的一个点,我们想办法用数据结构维护这个二维平面(注意根据题意这 ...
- bzoj 1176 cdq分治套树状数组
题面: 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Inp ...
- bzoj 4991 [Usaco2017 Feb]Why Did the Cow Cross the Road III(cdq分治,树状数组)
题目描述 Farmer John is continuing to ponder the issue of cows crossing the road through his farm, intro ...
- UVA 11990 ``Dynamic'' Inversion (序列分治)
26天以前做过的一道题,之前的做法是分治预处理,树套树在线修改,复杂度为O(nlogn+m*logn*logn),代码量较大. 本来想学习一下cdq分治的,看到论文上的凸包.斜率就暂时放一边了,只知道 ...
- 【BZOJ4285】使者 cdq分治+扫描线+树状数组
[BZOJ4285]使者 Description 公元 8192 年,人类进入星际大航海时代.在不懈的努力之下,人类占领了宇宙中的 n 个行星,并在这些行星之间修建了 n - 1 条星际航道,使得任意 ...
- HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
Jam's problem again Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Othe ...
- BZOJ 2716 [Violet 3]天使玩偶 (CDQ分治、树状数组)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2716 怎么KD树跑得都那么快啊..我写的CDQ分治被暴虐 做四遍CDQ分治,每次求一个 ...
- 【CJOJ2616】 【HZOI 2016】偏序 I(cdq分治,树状数组)
传送门 CJOJ Solution 考虑这是一个四维偏序对吧. 直接cdq套在一起,然后这题有两种实现方法(树状数组的更快!) 代码实现1(cdq+cdq+cdq) /* mail: mleautom ...
- bzoj2253纸箱堆叠(动态规划+cdq分治套树状数组)
Description P 工厂是一个生产纸箱的工厂.纸箱生产线在人工输入三个参数 n p a , 之后,即可自动化生产三边边长为 (a mod P,a^2 mod p,a^3 mod P) (a^4 ...
随机推荐
- Windows下pipenv将虚环境文件的位置设置在项目根目录下
在windows下使用pipenv shell时,虚拟环境文件夹会在C:\Users\Administrator\.virtualenvs\目录下默认创建,为了方便管理,将这个虚环境的文件的位置更改一 ...
- 用aws cli 下载s3中数据到本地
参考https://blog.csdn.net/DynastyRumble/article/details/76649120 1 首先注册AWS账户,绑定信用卡.一定要填写正确的手机,因为验证方式是它 ...
- 用原生js来处理跨域的数据(jsonp)
说明总结: 1.ajax和jsonp其实本质上是不同的东西.ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提 ...
- vue面试
1.一个比较全的vue面试题 http://www.bslxx.com/p/3187.html
- C# 读取word2003 并且显示在界面上的方法
1.新建一个windows窗体程序 2. 引入包WinWordControl.dll 3.添加引用 4.引入组件WinWordControl组件 5.主界面上加入按钮 ,opendialog, win ...
- 开发自己的R包(转)
R不必说,数据统计分析可视化的必备语言,R包开发的门槛比较低,所以现在随便一篇文章都会发表一个自己的R包,这样有好处(各种需求早有人帮你解决了)也有坏处(R包太多,混乱,新手上手较难).作为生信工程师 ...
- 20165327 2017-2018-2 《Java程序设计》第2周学习总结
20165327 2017-2018-2 <Java程序设计>第2周学习总结 内容:教材第2.3章 内容小结: (一)标识符由字母.下划线.美元符号和数字组成, 并且第一个字符不能是数字字 ...
- 详细讲解Linux下安装python3(Python3.5.4)
https://jingyan.baidu.com/article/6b97984dd6dbb01ca2b0bf0a.html
- G.711是一种由国际电信联盟(ITU-T)制定的音频编码方式
http://zh.wikipedia.org/zh-cn/G.711 ITU-T G.711 page ITU-T G.191 software tools for speech and audio ...
- codeforces 848B Rooter's Song 思维题
http://codeforces.com/problemset/problem/848/B 给定一个二维坐标系,点从横轴或纵轴垂直于发射的坐标轴射入(0,0)-(w,h)的矩形空间.给出点发射的坐标 ...