题解 CF1051G【Distinctification】

Link

题意

给你两个长为 n 的序列 ab,你可以进行两种操作若干次:

  1. 若有 ijai=aj,则可以令 aiai+1,代价为 bi
  2. 若有 ai=aj+1,则可以令 aiai1,代价为 bi

对于 i[1,n],求出最小的代价使得 a1i 互不相同。

1n,ai2×105b 为一个 [1,n] 的排列。

思路

最终的代价只与 ai 最终的值有关。

在一个值域连续段中,ai 的值无论如何操作都无法小于最小值,所以只是将 aibi 重新排序使得答案最小的问题。

可以发现,若 ai=aj+1,则可以交换 aiaj,并花费 bjbi 的代价。所以如果 ai 在一个值域上的连续段中,则可以将 bi 降序排序,使得代价最小。

我们需要维护每个值域连续段并支持合并,考虑线段树合并。

对每个值域连续段的左端点建立权值线段树,以 bi 为下标,考虑到可以视为将小于 mid 的值整体右移,答案为 sumrt×l+sumls×sizrs

用并查集找到连续段左端点并记录相应右端点。

数组记得开两倍。

时间复杂度 O(nlogn)

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int N=4e5+10;
int n,f[N],br[N];
ll ans;
inline int find(int x){
    return x==f[x]?x:f[x]=find(f[x]);
}
int rt[N];
struct Segument_Tree{
    int son[2][N*60],cnt;
    int siz[N*60];
    ll sum[N*60];
    #define ls (son[0][rt])
    #define rs (son[1][rt])
    inline void pushup(int rt){
        sum[rt]=sum[ls]+sum[rs];
        siz[rt]=siz[ls]+siz[rs];
    }
    inline void insert(int &rt,int l,int r,int p){
        if(!rt)
            rt=++cnt;
        if(l==r){
            sum[rt]=p,siz[rt]=1;
            return ;
        }
        int mid=l+r>>1;
        if(p<=mid) insert(ls,l,mid,p);
        else insert(rs,mid+1,r,p);
        pushup(rt);
    }
    inline int merge(int a,int b,int l,int r){
        if(!a||!b) return a+b;
        int rt=++cnt;
        if(l==r) return rt;
        ans-=sum[son[0][a]]*siz[son[1][a]]+
            sum[son[0][b]]*siz[son[1][b]];
        int mid=l+r>>1;
        ls=merge(son[0][a],son[0][b],l,mid);
        rs=merge(son[1][a],son[1][b],mid+1,r);
        ans+=sum[ls]*siz[rs];
        pushup(rt);
        return rt;
    }
}t;
inline void solve(int u,int v){
    u=find(u),v=find(v),f[v]=u;
    ans-=t.sum[rt[u]]*u+t.sum[rt[v]]*v;
    rt[u]=t.merge(rt[u],rt[v],1,n);
    ans+=t.sum[rt[u]]*u;
    br[u]=br[v];
}
int main(){
    n=read();
    for(int i=1;i<=N-10;i++)
        f[i]=br[i]=i;
    for(int i=1;i<=n;i++){
        int p=read(),v=read();
        int xp=rt[p]?br[find(p)]+1:p;
        ans+=1ll*(xp-p)*v;
        t.insert(rt[xp],1,n,v);
        if(rt[xp-1]) solve(xp-1,xp);
        if(rt[xp+1]) solve(xp,xp+1);
        write(ans),putc('\n');
    }
    flush();
}

再见 qwq~

posted @   ffffyc  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
历史上的今天:
2021-08-02 题解 P4155【[SCOI2015]国旗计划】
2021-08-02 题解 UVA1566【John】
点击右上角即可分享
微信分享提示