1 条题解

  • 0
    @ 2025-8-24 22:49:57

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar liuhangxin
    这个家伙很懒,真的什么都没写

    搬运于2025-08-24 22:49:57,当前版本为作者最后更新于2024-05-29 22:10:22,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P9596 [JOI Open 2018] 冒泡排序 2

    一个序列 AA 的扫描次数为 maxi=1nj=1i[aj>ai]\max_{i=1}^n \sum_{j=1}^i[a_j>a_i]

    证明:

    发现一次操作必定将恰好一个 pp 前面大于他的数换到他后面(排除没有的)。原式子相当于对于每个位置 pp ,把其前面大于他的换到他后面需要的扫描次数取 max\max ,即操作后对于每个位置其前面没有大于他的,序列 AA 就是拍好序列。

    发现同样的值只有最后一个位置 pp 有用,一种值的答案为 [Ai>v](np)\sum [A_i>v]-(n-p),其中可以把 npn-p 看作后面比他大的值,因为如果后面有比他小的值 v2v2 ,他的最后一个位置 p2>pp2>p,一定有 [Ai>v2](np2)>[Ai>v](np)\sum [A_i>v2]-(n-p2)>\sum [A_i>v]-(n-p) ,即值 vv 一定不优。

    开棵权值线段树直接维护这个式子的最值,用 set 维护每种颜色的位置集合即可。

    代码如下:

    #include<bits/stdc++.h>
    #define ll long long
    #define pii pair<int,int>
    #define fi first
    #define se second
    using namespace std;
    const int N=1e6+10,inf=1e9;
    int n,q;
    int a[N],stk[N],cnt;
    int p[N],v[N];
    set<int>s[N];
    int Max[4*N],tag[4*N];
    #define mid (l+r)/2
    #define L 2*u
    #define R 2*u+1
    void change(int u,int l,int r,int lp,int rp,int v)
    {
        if(lp>rp)return;
        if(lp<=l&&r<=rp)
        {
            Max[u]+=v;
            tag[u]+=v;
            return;
        }
        if(lp<=mid)change(L,l,mid,lp,rp,v);
        if(rp>mid)change(R,mid+1,r,lp,rp,v);
        Max[u]=max(Max[L],Max[R])+tag[u];
    }
    void Add(int c,int p){
        change(1,1,cnt,1,c-1,1);
        if(!s[c].size())change(1,1,cnt,c,c,inf-n);
        else change(1,1,cnt,c,c,-*prev(s[c].end()));
        s[c].insert(p);
        change(1,1,cnt,c,c,*prev(s[c].end()));
    }
    void Del(int c,int p)
    {
        change(1,1,cnt,1,c-1,-1);
        change(1,1,cnt,c,c,-*prev(s[c].end()));
        s[c].erase(p);
        if(!s[c].size())change(1,1,cnt,c,c,-(inf-n));
        else change(1,1,cnt,c,c,*prev(s[c].end()));
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),stk[++cnt]=a[i];
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d",&p[i],&v[i]);p[i]++;
            stk[++cnt]=v[i];
        }
        sort(stk+1,stk+cnt+1);
        cnt=unique(stk+1,stk+cnt+1)-stk-1;
        for(int i=1;i<=cnt;i++)change(1,1,cnt,i,i,-inf);
        for(int i=1;i<=n;i++)a[i]=lower_bound(stk+1,stk+cnt+1,a[i])-stk;
        for(int i=1;i<=q;i++)v[i]=lower_bound(stk+1,stk+cnt+1,v[i])-stk;
        for(int i=1;i<=n;i++)
            Add(a[i],i);
        for(int i=1;i<=q;i++)
        {
            Del(a[p[i]],p[i]);
            a[p[i]]=v[i];
            Add(a[p[i]],p[i]);
            printf("%d\n",Max[1]);
        }
        return 0;
    }
    
    • 1

    [JOI Open 2018] 冒泡排序 2 / Bubble Sort 2

    信息

    ID
    9158
    时间
    5000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者