CodeForces 899E Segments Removal

题解:

这题解法比较多样,核心思路都是模拟,只是实现的方法不一样。我的话是采用并查集+堆来维护。并查集要维护三个值:这一团的数字个数,这一团最左边的数字,这一团最右边的数字(这些都是可以直接暴力合并的),然后用堆来维护最大的区间,每次取出来判断一下是否已经被删去,没有就计入答案然后更新并查集和堆就可以了。

代码如下:

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;

int n,ans;
int a[200010],s[200010];
int fa[200010],sum[200010],lft[200010],rht[200010];
bool f[200010]; 

struct node{
	int id,sum;
	bool operator <(const node &T)const{return sum<T.sum||(sum==T.sum&&id>T.id);}
};

priority_queue<node> Q;

int find(int x)
{
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}

void merge(int a,int b)
{
	a=find(a);b=find(b);
	if(a==b) return ;
	if(sum[a]<sum[b]) swap(a,b);
	fa[b]=a;sum[a]+=sum[b];lft[a]=min(lft[a],lft[b]);rht[a]=max(rht[a],rht[b]);
}

int main()
{
	int x;
	node b;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
	   scanf("%d",&a[i]);fa[i]=lft[i]=rht[i]=i;sum[i]=1;
	   if(a[i]==a[i-1]){s[i]=s[i-1];merge(i,i-1);}
	   else s[i]=i;
	}
	for(int i=1;i<=n;i++){x=find(i);if(!f[x]){f[x]=1;Q.push((node){lft[x],sum[x]});}}
	while(!Q.empty())
	{
	  b=Q.top();Q.pop();x=find(b.id);
	  while(!f[x]&&!Q.empty()){b=Q.top();Q.pop();x=find(b.id);}
	  if(!f[x]&&Q.empty()) break;
	  ans++;f[x]=0;
	  while(lft[x]>1&&!f[find(lft[x]-1)]){merge(x,lft[x]-1);x=find(x);}
	  while(rht[x]<n&&!f[find(rht[x]+1)]){merge(x,rht[x]+1);x=find(x);}
	  if(lft[x]>1&&rht[x]<n&&a[lft[x]-1]==a[rht[x]+1])
	  {merge(lft[x]-1,rht[x]+1);Q.push((node){lft[find(lft[x]-1)],sum[find(lft[x]-1)]});}
	}
	printf("%d\n",ans);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值