【BZOJ2141】排队

这道题和动态逆序对比较像(BZOJ-3295 没做过的同学建议先做这题),只是删除操作变成了交换。解法:交换操作可以变成删除加插入操作,那么这题就变成了 (时间,位置,值)的三维偏序问题,考虑用CDQ分治解决:时间排序,位置分治,值树状数组。

但是这里要特别注意的是:本题因为有多个插入删除操作,所以多能会有多个操作的位置是相同的,但是逆序对要求的是位置比它小/大,值比它大/小的对,就是位置相等的不能算贡献。所以我们对CDQ分治的第二维的归并顺序就有讲究:必须是位置严格小于才放到左边然后插入树状数组,也就是说左边位置必须严格小于右边位置才算贡献。

其实这样说也不太对,(蒟蒻开始口胡)应该说CDQ分治的本质是:对于一个询问,它的答案就是所有比它早的修改对这个询问产生的影响累加的结果。也就是说其实分治的顺序并不是十分重要,只要达到了上面这个目标即可,但是往往我们为了方便统计答案会修改分治顺序使得这样做利于统计答案。举个例子就是像这题哪怕把分治顺序改为return x<rhs.x || x==rhs.x && z<rhs.z;只要把统计答案改为Q[p].x<Q[q].x其实也是OK的,只不过会使得分治和统计答案分开了而已。

细节见代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+;
int n,m,qid,a[N],b[N],ans[N];
struct rec{
int x,y,z,aid; //位置,插入/删除,值,答案下标
bool operator < (const rec &rhs) const {
return x<rhs.x;
}
}Q[N],tmp[N]; int sum[N];
void update(int x,int v) {
for (;x<=n;x+=x&-x) sum[x]+=v;
}
int query(int x) {
int ret=;
for (;x;x-=x&-x) ret+=sum[x];
return ret;
} void CDQ(int l,int r) {
if (l>=r) return;
int mid=l+r>>;
CDQ(l,mid); CDQ(mid+,r);
int p=l,q=mid+,o=l-;
while (p<=mid || q<=r) //归并排序结果
if (q>r || p<=mid && Q[p]<Q[q]) tmp[++o]=Q[p++]; else tmp[++o]=Q[q++]; p=l; q=mid+;
while (p<=mid || q<=r) //正向算逆序对
if (q>r || p<=mid && Q[p]<Q[q]) update(Q[p].z,Q[p].y),p++;
else ans[Q[q].aid]+=Q[q].y*(query(n)-query(Q[q].z)),q++;
for (int i=l;i<=mid;i++) update(Q[i].z,-Q[i].y); p=mid; q=r;
while (p>=l || q>mid) //反向算逆序对
if (q<=mid || p>=l && Q[q]<Q[p]) update(Q[p].z,Q[p].y),p--;
else ans[Q[q].aid]+=Q[q].y*(query(Q[q].z-)),q--;
for (int i=l;i<=mid;i++) update(Q[i].z,-Q[i].y); for (int i=l;i<=r;i++) Q[i]=tmp[i];
} int main()
{
cin>>n;
for (int i=;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
sort(b+,b+n+);
int t=unique(b+,b+n+)-(b+);
for (int i=;i<=n;i++) a[i]=lower_bound(b+,b+t+,a[i])-b;
for (int i=;i<=n;i++) Q[++qid]=(rec){i,,a[i],}; cin>>m;
for (int i=;i<=m;i++) {
int x,y; scanf("%d%d",&x,&y);
Q[++qid]=(rec){x,-,a[x],i};
Q[++qid]=(rec){x,,a[y],i};
Q[++qid]=(rec){y,-,a[y],i};
Q[++qid]=(rec){y,,a[x],i};
swap(a[x],a[y]);
} CDQ(,qid);
for (int i=;i<=m;i++) {
if (i) ans[i]+=ans[i-];
printf("%d\n",ans[i]);
}
return ;
}

BZOJ 2141 排队 (CDQ分治)的更多相关文章

  1. BZOJ 2141: 排队 [CDQ分治]

    题意: 交换序列中两个元素,求逆序对 做分块做到这道题...一看不是三维偏序嘛.... 作为不会树套树的蒟蒻就写CDQ分治吧.... 对时间分治...x排序...y树状数组... 交换拆成两个插入两个 ...

  2. bzoj 2141 : 排队 (cdq分治+bit)

    链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2141 思路: 其实就是求动态逆序对...cdq降维,用树状数组前后求两遍逆序对就好了 切水 ...

  3. [BZOJ 3456]城市规划(cdq分治+FFT)

    [BZOJ 3456]城市规划(cdq分治+FFT) 题面 求有标号n个点无向连通图数目. 分析 设\(f(i)\)表示\(i\)个点组成的无向连通图数量,\(g(i)\)表示\(i\)个点的图的数量 ...

  4. [BZOJ 2989]数列(CDQ 分治+曼哈顿距离与切比雪夫距离的转化)

    [BZOJ 2989]数列(CDQ 分治) 题面 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[y]| ...

  5. bzoj 4237 稻草人 - CDQ分治 - 单调栈

    题目传送门 传送点I 传送点II 题目大意 平面上有$n$个点.问存在多少个矩形使得只有左下角和右上角有点. 考虑枚举左下角这个点.然后看一下是个什么情况: 嗯对,是个单调栈.但不可能暴力去求每个点右 ...

  6. bzoj 3262 陌上花开 - CDQ分治 - 树状数组

    Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...

  7. bzoj 2141: 排队

    2141: 排队 Time Limit: 4 Sec Memory Limit: 259 MB Description 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我, ...

  8. Bzoj 2141: 排队 分块,逆序对,树状数组

    2141: 排队 Time Limit: 4 Sec  Memory Limit: 259 MBSubmit: 1310  Solved: 517[Submit][Status][Discuss] D ...

  9. bzoj 2141 : 排队 分块

    题目链接 2141: 排队 Time Limit: 4 Sec  Memory Limit: 259 MBSubmit: 1169  Solved: 465[Submit][Status][Discu ...

随机推荐

  1. zabbix邮件报警通过脚本来发送邮件

    zabbix默认邮件报警会将各个报警接收人单独发送邮件,为了使邮件能以群发的方式统一一封邮件发送所有接收人,需要改成脚本的形式: sendemail.py: #!/usr/bin/python imp ...

  2. 【leetcode】778. Swim in Rising Water

    题目如下: 解题思路:本题题干中提到了一个非常重要的前提:"You can swim infinite distance in zero time",同时也给了一个干扰条件,那就是 ...

  3. 027:for标签使用详解

    for标签使用详解: for...in... 标签: for...in... 类似于 Python 中的 for...in... .可以遍历列表.元组.字符串.字典等一切可以遍历的对象.示例代码如下: ...

  4. luogu P1307 数字反转 x

    题目描述 给定一个整数,请将该数各个位上数字反转得到一个新数.新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零(参见样例2). 输入输出格式 输入格式: 输入 ...

  5. 【テンプレート】RMQ

    1174 区间中最大的数 基准时间限制:1 秒 空间限制:131072 KB   收藏  关注 给出一个有N个数的序列,编号0 - N - 1.进行Q次查询,查询编号i至j的所有数中,最大的数是多少. ...

  6. 【Go】Go语言的%d,%p,%v等占位符的使用

    golang 的fmt 包实现了格式化I/O函数,类似于C的 printf 和 scanf. # 定义示例类型和变量 type Human struct { Name string } var peo ...

  7. ReactNative的学习笔记

    一.安装nodejs 查看是否安装:npm -v 二.安装react-native命令工具 npm install -g react-native-cli 三.查看 react-native --he ...

  8. 牛客2019提高D1t1 最短路

    分析 我们发现可以按照ai从小到大排序 边的大小就是当前的a减去前面第一个不等于它的a 代码 #include<iostream> #include<cstdio> #incl ...

  9. P3956棋盘

    传送 这看起来有点像个搜索,那我们就用搜索试试. dfs?bfs? 其实都可以,但是窝只会dfs.. 既然这里要用dfs,那么就要把每次搜到(m,m)时,使用的金币数量进行比较,取最小值. 在搜索过程 ...

  10. leetcode 190. 颠倒二进制位(c++)

    颠倒给定的 32 位无符号整数的二进制位. 示例 1: 输入: 00000010100101000001111010011100输出: 00111001011110000010100101000000 ...