【题目】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=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}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>?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=; 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=;
for(int i=;i<=n;i++)a[i]=read();
for(int i=;i<=n;i++){
x++;
if(a[i]!=a[i+]){
b[++tot]=(cyc){tot,x,a[i],i};
x=;
}
}
n=tot;
for(int i=;i<=n;i++)fa[i]=i,r[i]=i;
for(int i=;i<=n;i++)q.push(b[i]);
for(int i=;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-);else printf("%d",i);return ;}
//printf("%d %d %d %d\n",x.id,x.ans,x.number,x.l);
int f=find(x.id);
fa[f]=find(f-);r[fa[f]]=r[f];
int pre=find(f-),suc=find(r[f]+);
if(pre==||suc==||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 ;
}

【CodeForces】899 E. Segments Removal的更多相关文章

  1. 【CodeForces】899 F. Letters Removing

    [题目]F. Letters Removing [题意]给定只含小写字母.大写字母和数字的字符串,每次给定一个范围要求删除[l,r]内的字符c(l和r具体位置随删除变动),求m次操作后的字符串.n&l ...

  2. 【CodeForces】901 C. Bipartite Segments

    [题目]C. Bipartite Segments [题意]给定n个点m条边的无向连通图,保证不存在偶数长度的简单环.每次询问区间[l,r]中包含多少子区间[x,y]满足只保留[x,y]之间的点和边构 ...

  3. 【Luogu3602】Koishi Loves Segments(贪心)

    [Luogu3602]Koishi Loves Segments(贪心) 题面 洛谷 题解 离散区间之后把所有的线段挂在左端点上,从左往右扫一遍. 对于当前点的限制如果不满足显然会删掉右端点最靠右的那 ...

  4. 【CF429E】Points and Segments(欧拉回路)

    [CF429E]Points and Segments(欧拉回路) 题面 CF 洛谷 题解 欧拉回路有这样一个性质,如果把所有点在平面内排成一行,路径看成区间的覆盖,那么每个点被从左往右的覆盖次数等于 ...

  5. 【CF429E】Points and Segments 欧拉回路

    [CF429E]Points and Segments 题意:给你数轴上的n条线段$[l_i,r_i]$,你要给每条线段确定一个权值+1/-1,使得:对于数轴上的任一个点,所有包含它的线段的权值和只能 ...

  6. 【Codeforces】Round #491 (Div. 2) 总结

    [Codeforces]Round #491 (Div. 2) 总结 这次尴尬了,D题fst,E没有做出来.... 不过还好,rating只掉了30,总体来说比较不稳,下次加油 A:If at fir ...

  7. 【Codeforces】Round #488 (Div. 2) 总结

    [Codeforces]Round #488 (Div. 2) 总结 比较僵硬的一场,还是手速不够,但是作为正式成为竞赛生的第一场比赛还是比较圆满的,起码没有FST,A掉ABCD,总排82,怒涨rat ...

  8. 【CodeForces】601 D. Acyclic Organic Compounds

    [题目]D. Acyclic Organic Compounds [题意]给定一棵带点权树,每个点有一个字符,定义一个结点的字符串数为往下延伸能得到的不重复字符串数,求min(点权+字符串数),n&l ...

  9. 【Codeforces】849D. Rooter's Song

    [算法]模拟 [题意]http://codeforces.com/contest/849/problem/D 给定n个点从x轴或y轴的位置p时间t出发,相遇后按对方路径走,问每个数字撞到墙的位置.(还 ...

随机推荐

  1. 在MySQL中如何使用覆盖索引优化limit分页查询

    背景 今年3月份时候,线上发生一次大事故.公司主要后端服务器发生宕机,所有接口超时.宕机半小时后,又自动恢复正常.但是过了2小时,又再次发生宕机. 通过接口日志,发现MySQL数据库无法响应服务器.在 ...

  2. js 实现路由功能

    class Router { constructor() { this.routes = [] } handle(pattern, handler) { this.routes.push({ patt ...

  3. Delphi中的ADOquery 用法以及ADOquery的自有方法Append 和Delete和 Edit 和Post

    Delphi在数据库操作是非常好用的,delphi把ADO一些方法属性都集成了,以下是我的一些总结:*******************************通过sql的存储过程来实现:添加Wit ...

  4. Spring boot整合shiro框架

    ShiroConfiguration package com.energy.common.config; import java.util.LinkedHashMap; import java.uti ...

  5. 【bzoj1430】小猴打架 Prufer序列

    题目描述 给出 $n$ 个点,每次选择任意一条边,问这样 $n-1$ 次后得到一棵树的方案数是多少. 输入 一个整数N. 输出 一行,方案数mod 9999991. 样例输入 4 样例输出 96 题解 ...

  6. IDEA使用switch传入String编译不通过

    今天在使用IDEA的时候,用到switch分支语句,传入String参数的时候一直报错,下面是源码报错截图: 看错误提示并没有提到switch支持String类型,不过ava1.7之后就支持Strin ...

  7. BZOJ3743 COCI2015Kamp(树形dp)

    设f[i]为由i开始遍历完子树内所要求的点的最短时间,g[i]为由i开始遍历完子树内所要求的点最后回到i的最短时间.则g[i]=Σ(g[j]+2),f[i]=min{g[i]-g[j]+f[j]-1} ...

  8. 获取和验证Windows AD域的用户信息

    1.获取windows AD域用户信息,首先需要有一个ad域管理员权限的账号,用这个账号连接ad域,获取所有域用户信息 用LdapContext,它继承自DirContext public Objec ...

  9. 【WebAPI】新手入门WebAPI

    一.前言       工作也有一年多了,从进入公司就一直进行BIM(建筑信息模型)C/S产品的研发,平时写的最多的就是Dev WPF.一个偶然的时机,产品需要做支付宝扫码与微信扫码,所以需要了解产品服 ...

  10. 浴谷八连测R4题解

    一开始出了点bug能看见排行榜,于是我看见我半个小时就A掉了前两题,信心场QAQ T1字符串题就不说了qwq #include<iostream> #include<cstring& ...