zoukankan      html  css  js  c++  java
  • 【CodeForces】899 E. Segments Removal

    【题目】E. Segments Removal

    【题意】给定n个数字,每次操作删除最长的连续相同数字(等长删最左),求全部删完的最少次数。n<=2*10^6,1<=ai<=10^9。

    【算法】并查集+堆

    【题解】将序列的相同数字段压缩,全部插入堆。那么每次操作删除堆顶,并尝试合并堆顶的前驱和后继,能合并就重新插入堆中。

    在支持删除的序列中找前驱和后继,是经典的并查集实现。

    具体而言,fa[i]表示 i 点左边(含自身)最近的未被删除的点,即把删除了的点全部并入左侧第一个未被删除的点,那么删除点x后fa[x]=find(fa[x]-1)。

    前驱是find(fa[x]-1),后继只需要记录r[x]表示x点代表区间的最右端点,每次合并是:fa[y]=x,r[x]=r[y]。

    如果能合并就重新插入堆中,容易发现堆中废弃的元素一定比新插入的更晚访问,所以废弃元素访问到就会是被删除的现象,一个元素被删除表现为find(x) ≠ x。

    注意:删除的时候记得更新r[]。

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<set>
    #include<vector>
    #include<algorithm>
    #define ll long long
    #define lowbit(x) x&-x
    using namespace std;
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    int min(int a,int b){return a<b?a:b;}
    int max(int a,int b){return a<b?b:a;}
    int ab(int x){return x>0?x:-x;}
    //int MO(int x){return x>=MOD?x-MOD:x;}
    //void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
    /*------------------------------------------------------------*/
    const int inf=0x3f3f3f3f,maxn=200010;
    
    int n,fa[maxn],a[maxn],tot,r[maxn];
    struct cyc{
        int id,ans,number,l;
        bool operator < (const cyc &a)const{
            return ans<a.ans||(ans==a.ans&&l>a.l);
        }
    }b[maxn];
    priority_queue<cyc>q;
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    int main(){
        n=read();
        int x=0;
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=1;i<=n;i++){
            x++;
            if(a[i]!=a[i+1]){
                b[++tot]=(cyc){tot,x,a[i],i};
                x=0;
            }
        }
        n=tot;
        for(int i=1;i<=n;i++)fa[i]=i,r[i]=i;
        for(int i=1;i<=n;i++)q.push(b[i]);
        for(int i=1;i<=n;i++){
            cyc x=q.top();q.pop();
            while(find(x.id)!=x.id&&!q.empty())x=q.top(),q.pop();
            if(q.empty()){if(find(x.id)!=x.id)printf("%d",i-1);else printf("%d",i);return 0;}
            //printf("%d %d %d %d
    ",x.id,x.ans,x.number,x.l);
            int f=find(x.id);
            fa[f]=find(f-1);r[fa[f]]=r[f];
            int pre=find(f-1),suc=find(r[f]+1);
            if(pre==0||suc==0||b[pre].number!=b[suc].number)continue;
            fa[suc]=pre;
            b[pre].ans+=b[suc].ans;
            r[pre]=r[suc];
            q.push(b[pre]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    [日常工作]WorkStation 使用端口转发的方式使用宿主机IP地址提供服务
    [日常工作]虚拟机或者实体机转换成HyperV虚拟机的方法
    [linux学习]sysctl 以及 net.ipv4.ip_forward
    [自学]Docker system 命令 查看docker镜像磁盘占用情况 Docker volume 相关
    Docker 修改默认存储路径的一个方法
    [学习笔记]Ubuntu下安装配置SQLSERVER2017
    VSCODE安装以及使用Python运行调试代码的简单记录
    Win2012r2 以及win2016 安装.NET3.5
    Win2016以及win10 IIS10 下安装IEwebcontrol的方法
    [日常工作]协助同事从不能开机的机器上面获取资料信息
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8057271.html
Copyright © 2011-2022 走看看