[CF1830E] Bully Sort
题目描述
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的更多相关文章
- [算法]——归并排序(Merge Sort)
归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序:然后将已经有序的两个子部分进行合并,最终完成排序.其时间复杂度与快速排序均为O(nlog ...
- [算法]——快速排序(Quick Sort)
顾名思义,快速排序(quick sort)速度十分快,时间复杂度为O(nlogn).虽然从此角度讲,也有很多排序算法如归并排序.堆排序甚至希尔排序等,都能达到如此快速,但是快速排序使用更加广泛,以至于 ...
- shell之sort命令
1 sort的工作原理 sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出. [rocrocket@rocrocket progr ...
- 详细解说 STL 排序(Sort)
0 前言: STL,为什么你必须掌握 对于程序员来说,数据结构是必修的一门课.从查找到排序,从链表到二叉树,几乎所有的算法和原理都需要理解,理解不了也要死记硬背下来.幸运的是这些理论都已经比较成熟,算 ...
- SQL Tuning 基础概述06 - 表的关联方式:Nested Loops Join,Merge Sort Join & Hash Join
nested loops join(嵌套循环) 驱动表返回几条结果集,被驱动表访问多少次,有驱动顺序,无须排序,无任何限制. 驱动表限制条件有索引,被驱动表连接条件有索引. hints:use_n ...
- js sort() reverse()
数组中存在的两个方法:sort()和reverse() 直接用sort(),如下: ,,,,,,,,,,,]; console.log(array.sort());ps:[0, 1, 2, 2, 29 ...
- Java中的经典算法之冒泡排序(Bubble Sort)
Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...
- 2.sort 排序命令讲解
sort命令 sort:文本排序,仅仅是对显示文件的排序,而不影响源文件的顺序,是根据ASSII码 的字符升序来排列的. -n:安装数值大小从小到大排列 ,默认是升序. ...
- 基本shell编程【3】- 常用的工具awk\sed\sort\uniq\od
awk awk是个很好用的东西,大量使用在linux系统分析的结果展示处理上.并且可以使用管道, input | awk '' | output 1.首先要知道形式 awk 'command' fi ...
- 快速排序算法 quick sort的理解
最近做了一下算法的一些练习,感觉基础薄弱了,只是用一些已经有的东西来完成练习如quickSort(c++使用的时候是sort(起始位置,终止位置,比较函数),这个需要加头文件),但是不知道怎么推出来, ...
随机推荐
- 《最新出炉》系列初窥篇-Python+Playwright自动化测试-13-playwright操作iframe-下篇
1.简介 通过前边两篇的学习,想必大家已经对iframe有了一定的认识和了解,今天这一篇主要是对iframe做一个总结,主要从iframe的操作(输入框.点击等等)和定位两个方面进行总结. 2.ifr ...
- Android13深入了解 Android 小窗口模式和窗口类型
Android13深入了解 Android 小窗口模式和窗口类型 小窗模式,作为一种在移动设备上的多任务处理方式,为用户带来了便捷和高效的体验,尤其在一些特定场景下,其价值愈发凸显.以下是为什么需要小 ...
- Python操作Redis大全
一.字符串 string Python操作Redis的redis模块对字符串(string)的主要操作函数包括:SET.GET.GETSET.SETEX.SETNX.MSET.MSETNX.INCR( ...
- C# 异步执行操作
为了方便测试异步,先加个计时 计时相关(可以直接跳过该部分) //开始计时 Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); // 停 ...
- Leetcode刷题笔记——二分法
二分法是搜索算法中极其典型的方法,其要求输入序列有序并可随机访问.算法思想为 输入:有序数组nums,目的数值target 要求输出:如果target存在在数组中,则输出其index,否则输出-1 将 ...
- MIPS寄存器堆
实验目的 熟悉并掌握 MIPS 计算机中寄存器堆的原理和设计方法 理解源操作数/目的操作数的概念 实验环境 Vivado 集成开发环境 MIPS寄存器 寄存器R0的值恒为0. 模块接口设计 1个写端口 ...
- 【matplotlib基础】--图例
Matplotlib 中的图例是帮助观察者理解图像数据的重要工具.图例通常包含在图像中,用于解释不同的颜色.形状.标签和其他元素. 1. 主要参数 当不设置图例的参数时,默认的图例是这样的. impo ...
- C#结合OpenCVSharp4使用直方图算法比较图片相似度
C#结合OpenCVSharp4使用直方图算法比较图片相似度 直方图有灰度直方图.颜色直方图,如果是灰度图像,那么就用灰度直方图,这里使用颜色直方图来计算两个图片的相似度. 这里只记录如何使用,至于算 ...
- 基于Protege的知识建模实战
一.Protege简介.用途和特点 1.Protege简介 Protege是斯坦福大学医学院生物信息研究中心基于Java开发的本体编辑和本体开发工具,也是基于知识的编辑器,属于开放源代码软件.这个软件 ...
- selenium库浅析
selenium库浅析 基于4.3 pip install selenium安装好后,在sitepackages下 2个主要的目录,common和webdriver 1- common 该目录一共就一 ...