BZOJ5278&&洛谷P4375 [USACO18OPEN]Out of Sorts (金组)

智障(shang)题+树状数组维护前缀和

我们定义一下冒泡排序的分割点,分割点i的定义就是在他左边的点的rank都小于等于i,右边的rank都大于等于i,也就是说一个分割点出现后,他左边的点不会再跑到右边

定义si表示在排名在i之前的数不在i之前的个数

不难发现,题目给的程序跑一次,会使一个分割点左侧的点跑到右边(显然这个点是i左边最大的),一个右侧的点跑到左边(显然这是i右边最小的),然后就会使这个点的si-1,所以我们发现,排序的次数就是si点的最大值,然后因为即使是一开始的数列就有序,也要进一次冒泡,所以ans初始为1

代码

//By AcerMo
#include
#include
#include
#include
#include
#define lowbit(x) x&(-x)
#define lli long long int
using namespace std;
const int M=100500;
int n,s[M],rk[M];
struct bit{int a,id;}e[M];
inline int read()
{
    int x=0;char ch=getchar();
    while (ch>'9'||ch<'0') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
inline void add(int p,int x)
{
    for (int i=p;i<=n;i+=lowbit(i)) s[i]+=x;
    return ;
}
inline lli sum(int p)
{
    lli ans=0;
    for (int i=p;i;i-=lowbit(i)) ans+=s[i];
    return ans;
}
inline bool cmp(bit x,bit y){return x.asigned main()
{
    n=read();lli ans=1;
    for (int i=1;i<=n;i++) e[i].a=read(),e[i].id=i;
    stable_sort(e+1,e+n+1,cmp);
    for (int i=1;i<=n;i++) rk[e[i].id]=i;
    for (int i=1;i<=n;i++)
    {
        add(rk[i],1);
        ans=max(ans,i-sum(i));
    }
    cout<return 0;
}

你可能感兴趣的:(排序,数据结构-树状数组)