ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1270H Number of Components

2021-09-08 21:03:50  阅读:172  来源: 互联网

标签:01 int 个数 Number CF1270H Components 权值 序列 维护


一、题目

点此看题

二、解法

真的好题啊,我这个垃圾感受到了思维的锤炼。

一开始我想的是做单调栈,我们维护一个递减的单调栈,每次插入一个数就把权值小于它的元素合并到一起,定义合并元素的权值为原来所有元素的权值最小值,连通块个数就是最后栈中元素个数。

显然单调栈是动态维护不了的,但是我们可以从中看出一个奇妙的性质:连通块对应原序列的一个区间。

所以可以做一个问题转化,我们求出有多少个分界点 \(p\) 满足 \(\forall x\in[1,p],y\in[p+1,n],a_x>a_y\)

这个问题可以再转成对于原序列中的权值 \(v\),大于 \(v\) 的值设置为 \(0\),小于等于 \(v\) 的值设置成 \(1\),求生成 \(01\) 序列形如这样\(111...11000...00\) 的权值个数。

对于每个 \(v\) 我们维护生成序列 \(10\) 相邻数对的个数,如果数对个数为 \(1\) 就是合法的答案。可以用线段树维护,对于原序列上的两个位置 \(i,i+1\),\(v\in[\min(a_i,a_{i+1}),\max(a_i,a_{i+1}))\) 的数对个数会增加 \(1\),区间修改即可。

为了方便我们设 \(a_0=inf,a_{n+1}=-inf\),因为 \(10\) 数对个数至少为 \(1\),所以我们维护最小值和最小值的数量即可,时间复杂度 \(O(n\log n)\)

三、总结

对于排除错误的思路:单调栈是不可能动态维护的(除非特殊情况转成笛卡尔树),想清楚我们要的是什么(本题只需要求元素个数),那么我们把问题转化只关心我们想要的。

序列图论题的结论思考方向:图论某个量和原序列区间的联系。

序列大小关系的处理可以转 \(01\) 序列(比如著名的 \(01\) 原则),大于某个权值设为 \(1\),否则设为 \(0\),然后研究 \(01\) 序列的性质。

维护某一个特定值的数量,思考他是否一定是最值,是的话转成维护最值和最值的数量。

#include <cstdio>
#include <iostream>
using namespace std;
const int inf = 0x3f3f3f3f;
const int M = 1000005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,q,a[M],ad[4*M];
struct node
{
	int v,c;
	node(int V=inf,int C=0) : v(V) , c(C) {}
	node operator + (const node &b) const
	{
		node r;
		r.v=min(v,b.v);
		if(r.v==v) r.c+=c;
		if(r.v==b.v) r.c+=b.c;
		return r;
	}
}tr[4*M];
void add(int i,int x)
{
	ad[i]+=x;tr[i].v+=x;
}
void down(int i)
{
	if(!ad[i]) return ;
	add(i<<1,ad[i]);
	add(i<<1|1,ad[i]);
	ad[i]=0;
}
void up(int i)
{
	tr[i]=tr[i<<1]+tr[i<<1|1];
}
void ins(int i,int l,int r,int id,int f)
{
	if(l==r)
	{
		if(f==0) tr[i]=node(inf,0);
		else tr[i]=node(ad[i],1);
		return ; 
	}
	int mid=(l+r)>>1;down(i);
	if(mid>=id) ins(i<<1,l,mid,id,f);
	else ins(i<<1|1,mid+1,r,id,f);
	up(i);
}
void upd(int i,int l,int r,int L,int R,int x)
{
	if(L>r || l>R) return ;
	if(L<=l && r<=R)
	{
		add(i,x);
		return ;
	}
	int mid=(l+r)>>1;down(i);
	upd(i<<1,l,mid,L,R,x);
	upd(i<<1|1,mid+1,r,L,R,x);
	up(i);
}
void work(int i,int f)
{
	int l=min(a[i],a[i+1]),r=max(a[i],a[i+1]);
	upd(1,0,m,l,r-1,f);
}
int main()
{
	n=read();m=1e6;q=read();
	for(int i=1;i<=n;i++)
		a[i]=read(),ins(1,0,m,a[i],1);
	a[0]=m+1;a[n+1]=0;
	for(int i=0;i<=n;i++) work(i,1);
	while(q--)
	{
		int x=read();
		//delete
		work(x-1,-1);work(x,-1);ins(1,0,m,a[x],0);
		//add
		a[x]=read();
		work(x-1,1);work(x,1);ins(1,0,m,a[x],1);
		if(tr[1].v==1) printf("%d\n",tr[1].c);
		else puts("0");
	}
}

标签:01,int,个数,Number,CF1270H,Components,权值,序列,维护
来源: https://www.cnblogs.com/C202044zxy/p/15244536.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有