ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

noi online 提高组t2

2020-03-08 13:01:53  阅读:269  来源: 互联网

标签:排列 noi int t2 冒泡排序 online 操作 leqslant 逆序


题目描述

给定一个 1 ∼ n1∼n 的排列 p_ipi​,接下来有 mm 次操作,操作共两种:

  1. 交换操作:给定 xx,将当前排列中的第 xx 个数与第 x+1x+1 个数交换位置。
  2. 询问操作:给定 kk,请你求出当前排列经过 kk 轮冒泡排序后的逆序对个数。 对一个长度为 nn 的排列 p_ipi​ 进行一轮冒泡排序的伪代码如下:
for i = 1 to n-1:
  if p[i] > p[i + 1]:
    swap(p[i], p[i + 1])

输入格式

第一行两个整数 nn, mm,表示排列长度与操作个数。

第二行 nn 个整数表示排列 p_ipi​。

接下来 mm 行每行两个整数 t_iti​, c_ici​,描述一次操作:

  • 若 t_i=1ti​=1,则本次操作是交换操作,x=c_ix=ci​;
  • 若 t_i=2ti​=2,则本次操作是询问操作,k=c_ik=ci​。

输出格式

对于每次询问操作输出一行一个整数表示答案。

 

输入输出样例

输入 #1
3 6
1 2 3
2 0
1 1
1 2
2 0
2 1
2 2
输出 #1
0
2
1
0

说明/提示

样例一解释

第一次操作:排列为 \{1,2,3\},经过 0 轮冒泡排序后为 \{1,2,3\},0 个逆序对。

第二次操作:排列变为 \{2,1,3\}。

第三次操作:排列变为 \{2,3,1\}。

第四次操作:经过 0轮冒泡排序后排列变为 \{2,3,1\}{2,3,1},2 个逆序对。

第五次操作:经过 1 轮冒泡排序后排列变为 \{2,1,3\}{2,1,3},1 个逆序对。

第六次操作:经过 2轮冒泡排序后排列变为 \{1,2,3\}{1,2,3},0 个逆序对。


数据范围与提示

对于测试点 1 ∼ 2:nn, m \leqslant 100m⩽100。

对于测试点 3 ∼ 4:nn, m \leqslant 2000m⩽2000。

对于测试点 5 ∼ 6:交换操作个数不超过 100100。

对于所有测试点:2 \leqslant n2⩽n, m \leqslant 2 \times 10^5m⩽2×105,t_i \in \{1,2\}ti​∈{1,2},1 \leqslant x < n1⩽x<n,0 \leqslant k < 2^{31}0⩽k<231。

 

 

解析:

本题是个结论题。。。

手玩几组冒泡排序就会发现,经历一次冒泡排序会发生这样的事情:

如果一个数左边有比它大的数:这个数消除不了逆序对

否则,这个数可以一直向后交换,直到遇到比它大的数

简单理解:如果它左边有比它厉害的,它就被干掉了,

否则它就一直向右碾压,直到遇到它打不过的人再停下。

具体操作:

 

我们记录第i位数前面比它大的数的数量为b[i],显然,

当前序列的总逆序对数量就是所有的b之和通过对冒泡排序的观察

,我们可以发现,每一遍冒泡排序都会使得所有b[i]=max(b[i]-1,0)

 

我们采用树状数组差分维护这一操作,令quera(t)为当ti=2,k=t时的答案

 

在数组最前面加入当前序列总逆序对数量,然后在第i位放b大于i的数字的数量的相反数,

因为这些数字在第i轮逆序对数均会减1

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+5;
int n,m,a[maxn],b[maxn],d[maxn];
ll c[maxn],ans;
inline int lowbit(int x)
{
    return x&(-x);
}
inline void add(int x,ll val)
{
    while(x<=n)
	{
        c[x]+=val;
        x+=lowbit(x);
    }
}
inline ll quera(int x)
{
    ll res=0;
    while(x>0)
	{
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
int main()
{
    int opt,x,tmp=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
	{
        scanf("%d",&a[i]);
        b[i]=i-1-quera(a[i]);
        ans+=b[i],++d[b[i]];
        add(a[i],1);
    }
    memset(c,0,sizeof(c));
    add(1,ans);
    for(int i=0;i<n;i++)
	{
        tmp+=d[i];
        add(i+2,tmp-n);
    }
    for(int i=1;i<=m;i++)
	{
        scanf("%d%d",&opt,&x);
        x=min(x,n-1);
        if(opt==1)
		{
            if(a[x]<a[x+1])
			{
                swap(a[x],a[x+1]);
                swap(b[x],b[x+1]);
                add(1,1);
                add(b[x+1]+2,-1);
                b[x+1]++;
            }
            else
			{
                swap(a[x],a[x+1]);
                swap(b[x],b[x+1]);
                add(1,-1);
                b[x]--;
                add(b[x]+2,1);
            }
        }
        else printf("%lld\n",quera(x+1));
    }
    return 0;
}

  

标签:排列,noi,int,t2,冒泡排序,online,操作,leqslant,逆序
来源: https://www.cnblogs.com/chen-1/p/12442073.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有