题目描述

On a permutation $ p $ of length $ n $ , we define a bully swap as follows:

  • Let $ i $ be the index of the largest element $ p_i $ such that $ p_i \neq i $ .
  • Let $ j $ be the index of the smallest element $ p_j $ such that $ i < j $ .
  • Swap $ p_i $ and $ p_j $ .

We define $ f(p) $ as the number of bully swaps we need to perform until $ p $ becomes sorted. Note that if $ p $ is the identity permutation, $ f(p)=0 $ .

You are given $ n $ and a permutation $ p $ of length $ n $ . You need to process the following $ q $ updates.

In each update, you are given two integers $ x $ and $ y $ . You will swap $ p_x $ and $ p_y $ and then find the value of $ f(p) $ .

Note that the updates are persistent. Changes made to the permutation $ p $ will apply when processing future updates.

输入格式

The first line of the input contains two integers $ n $ and $ q $ ( $ 2 \le n \le 5 \cdot 10^5 $ , $ 1 \le q \le 5 \cdot 10^4 $ ) — the length of the permutation and the number of updates.

The second line of input contains $ n $ integer $ p_1,p_2,\ldots,p_n $ ( $ 1 \leq p_i \leq n $ ) — the permutation $ p $ . All elements of $ p $ are distinct.

The $ i $ -th of the next $ q $ lines of input contains two integers $ x_i $ and $ y_i $ ( $ 1 \le x_i < y_i \le n $ ) — describing the $ i $ -th update.

神仙题。

现在主要问题是如何快速求出 \(f(p)\) 的答案。

结论是 \(\sum\limits_{i=1}^n |i-p_i|-\sum\limits_{i=1}^n\sum\limits_{j=i+1}^n[a_i>a_j]\)

因为在一次交换 \(i,j\) 时,逆序对减少 \(2(j-i)-1\) 次,\(|i-p_i|\) 减少 \(2(j-i)\) 个,于是减一下就是答案。

然后动态维护逆序对就好,我打了个常数巨大的 KDT。

#include<bits/stdc++.h>
using namespace std;
const int N=6e5+5;
typedef long long LL;
LL ans;
int n,q,mxx[N],mnx[N],mxy[N],mny[N],idx,c[N],tr[N],g[N],p[N],m;
pair<int,int>a[N];
int cmp(pair<int,int>x,pair<int,int>y)
{
return x.second^y.second? x.second<y.second:x.first<y.first;
}
int ask(int l,int r,int u,int d)
{
int o=l+r>>1;
if(l>r||mnx[o]>u||mxy[o]<d)
return 0;
if(mxx[o]<=u&&mny[o]>=d)
return c[o];
return ask(l,o-1,u,d)+ask(o+1,r,u,d)+(a[o].first<=u&&a[o].second>=d&&g[o]);
}
int build(int l,int r,int op)
{
if(l>r)
return 0;
int o=l+r>>1;
if(!op)
nth_element(a+l,a+o,a+r+1);
else
nth_element(a+l,a+o,a+r+1,cmp);
int lc=build(l,o-1,!op),rc=build(o+1,r,!op);
mxx[o]=max({mxx[lc],mxx[rc],a[o].first});
mnx[o]=min({mnx[lc],mnx[rc],a[o].first});
mxy[o]=max({mxy[lc],mxy[rc],a[o].second});
mny[o]=min({mny[lc],mny[rc],a[o].second});
return o;
}
void add(int l,int r,int a0,int a1,int t,int op)
{
int o=l+r>>1;
c[o]+=t;
if(a0==a[o].first&&a1==a[o].second)
return g[o]+=t,void();
if(!op&&make_pair(a0,a1)<a[o]||op&&cmp(make_pair(a0,a1),a[o]))
return add(l,o-1,a0,a1,t,!op),void();
add(o+1,r,a0,a1,t,!op);
}
int read()
{
int s=0;
char ch=getchar();
while(ch<'0'||ch>'9')
ch=getchar();
while(ch>='0'&&ch<='9')
s=s*10+ch-48,ch=getchar();
return s;
}
void upd(int x)
{
for(;x<=n;x+=x&-x)
tr[x]++;
}
int query(int x)
{
int ret=0;
for(;x;x-=x&-x)
ret+=tr[x];
return ret;
}
void jia(int x,int op)
{
ans+=op*abs(x-p[x]);
int k=ask(1,m,x-1,p[x]);
ans-=op*k;
ans-=op*(p[x]-x+k);
}
int main()
{
static int x[N],y[N],g[N];
mnx[0]=mny[0]=1000000000;
mxx[0]=mxy[0]=-1;
n=read(),q=read();
for(int i=1;i<=n;i++)
g[i]=p[i]=read(),a[++m]=make_pair(i,p[i]);
for(int i=1;i<=q;i++)
{
x[i]=read(),y[i]=read();
swap(g[x[i]],g[y[i]]);
a[++m]=make_pair(x[i],g[x[i]]);
a[++m]=make_pair(y[i],g[y[i]]);
}
build(1,m,0);
for(int i=1;i<=n;i++)
add(1,m,i,p[i],1,0),upd(p[i]),ans+=abs(i-p[i])-i+query(p[i]);
for(int i=1;i<=q;i++)
{
jia(x[i],-1);
jia(y[i],-1);
add(1,m,x[i],p[x[i]],-1,0);
add(1,m,y[i],p[y[i]],-1,0);
if(p[x[i]]>p[y[i]])
--ans;
swap(p[x[i]],p[y[i]]);
add(1,m,x[i],p[x[i]],1,0);
add(1,m,y[i],p[y[i]],1,0);
jia(x[i],1);
jia(y[i],1);
if(p[x[i]]>p[y[i]])
++ans;
printf("%lld\n",ans);
}
}

[CF1830E] Bully Sort的更多相关文章

  1. [算法]——归并排序(Merge Sort)

    归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序:然后将已经有序的两个子部分进行合并,最终完成排序.其时间复杂度与快速排序均为O(nlog ...

  2. [算法]——快速排序(Quick Sort)

    顾名思义,快速排序(quick sort)速度十分快,时间复杂度为O(nlogn).虽然从此角度讲,也有很多排序算法如归并排序.堆排序甚至希尔排序等,都能达到如此快速,但是快速排序使用更加广泛,以至于 ...

  3. shell之sort命令

    1 sort的工作原理 sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出. [rocrocket@rocrocket progr ...

  4. 详细解说 STL 排序(Sort)

    0 前言: STL,为什么你必须掌握 对于程序员来说,数据结构是必修的一门课.从查找到排序,从链表到二叉树,几乎所有的算法和原理都需要理解,理解不了也要死记硬背下来.幸运的是这些理论都已经比较成熟,算 ...

  5. SQL Tuning 基础概述06 - 表的关联方式:Nested Loops Join,Merge Sort Join & Hash Join

    nested loops join(嵌套循环)   驱动表返回几条结果集,被驱动表访问多少次,有驱动顺序,无须排序,无任何限制. 驱动表限制条件有索引,被驱动表连接条件有索引. hints:use_n ...

  6. js sort() reverse()

    数组中存在的两个方法:sort()和reverse() 直接用sort(),如下: ,,,,,,,,,,,]; console.log(array.sort());ps:[0, 1, 2, 2, 29 ...

  7. Java中的经典算法之冒泡排序(Bubble Sort)

    Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...

  8. 2.sort 排序命令讲解

    sort命令  sort:文本排序,仅仅是对显示文件的排序,而不影响源文件的顺序,是根据ASSII码     的字符升序来排列的.        -n:安装数值大小从小到大排列 ,默认是升序.     ...

  9. 基本shell编程【3】- 常用的工具awk\sed\sort\uniq\od

    awk awk是个很好用的东西,大量使用在linux系统分析的结果展示处理上.并且可以使用管道, input | awk ''  | output 1.首先要知道形式 awk 'command' fi ...

  10. 快速排序算法 quick sort的理解

    最近做了一下算法的一些练习,感觉基础薄弱了,只是用一些已经有的东西来完成练习如quickSort(c++使用的时候是sort(起始位置,终止位置,比较函数),这个需要加头文件),但是不知道怎么推出来, ...

随机推荐

  1. 0×03 Vulnhub 靶机渗透总结之 KIOPTRIX: LEVEL 1.2 (#3) SQL注入+sudo提权

    0×03 Vulnhub 靶机渗透总结之 KIOPTRIX: LEVEL 1.2 (#3) 系列专栏:Vulnhub靶机渗透系列 欢迎大佬:点赞️收藏关注 首发时间: 2023年8月22日 如有错误 ...

  2. 用ChatGPT三分钟免费做出数字人视频- 提升自媒体魅力

    本教程收集于:AIGC从入门到精通教程汇总 操作指引 ChatGPT产生文案=>腾讯智影数字人播报=>粘贴文案=>导出视频. 说明:部分资源只有会员才能用~,非会员可生成5分钟视频. ...

  3. 《CTFshow-Web入门》02. Web 11~20

    @ 目录 web11 题解 原理 web12 题解 web13 题解 web14 题解 web15 题解 web16 题解 原理 web17 题解 web18 题解 原理 web19 题解 web20 ...

  4. 应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪 —— Ingress Controller + Http服务 + Grpc服务(三)

    1.概述 在<应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪(一)>这篇博文中,我们详细介绍了单个应用程序通过 Envoy 和 Jaeger 实现链路追踪的过程.通过这个示 ...

  5. Linux 干货整理(持续更新)

    博客地址:https://www.cnblogs.com/zylyehuo/ 如果虚拟机开机没有 ip 怎么办 1.vim编辑网卡配置文件,修改如下参数 [root@s25linux tmp]# cd ...

  6. MySQL篇:第一章_软件安装和基本操作

    本篇安装软件Navicate Premium 16破解版和phpstudy_pro phpstudy_pro安装教程 phpstudy官网:https://www.xp.cn/download.htm ...

  7. Python面向对象——property装饰器、继承(与python2不同点)、多继承(优缺点、Mixins)、属性查找、多继承带来的菱形问题

    文章目录 内容回顾 property装饰器 继承 与python2的差别 多继承 为何要用继承 如何实现继承 属性查找 多继承带来的菱形问题 总结: 作业 内容回顾 1.封装=>整合 人的对象. ...

  8. dig 简明教程

    哈喽大家好,我是咸鱼 不知道大家在日常学习或者工作当中用 dig 命令多不多 dig 是 Domain Information Groper 的缩写,对于网络管理员和在域名系统(DNS)领域工作的小伙 ...

  9. Util应用框架 UI 开发快速入门

    本文是Util应用框架 Angular UI 开发快速入门教程. Util前端技术概述 Util 应用框架目前仅支持用于开发管理后台的 UI. 本文介绍了 Util UI 的技术特点和功能支持. UI ...

  10. 针对Jupter Kernel error的问题解决

    首先打开Anaconda Prompt 输入jupyter kernelspec list查看安装的内核和位置 到显示的的目录下面找到 kernel.josn这个文件 修改为现在的python环境路径 ...