ICode9

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

cf1705E. Mark and Professor Koro

2022-07-16 16:02:16  阅读:208  来源: 互联网

标签:Koro return rs int Professor tf ls cf1705E tg


题意:

给长度为\(n\)的数列\(a\),每次可以删除两个相同的数\(x\),加入\(x+1\),此时\(n--\)。
问你能得到的最大的数是多少。
为了增加难度,给了你\(q\)次询问,每次修改一个数(对之后的询问都奏效),再问你同样的问题。

思路:

首先答案跟数列\(a\)的排列顺序无关,跟不同值的个数有关。
也容易想到有两个相同的数就马上把它们合并(这是它们唯一的作用,总不能留着过年
设\(c_i\)表示值\(i\)在\(a\)中出现次数。
\(c_i\)个值\(i\)可以变成\(\left\lfloor\frac{c_i}{2}\right\rfloor\)个\(i+1\),\(c_{i+1}+\left\lfloor\dfrac{c_i}{2}\right\rfloor\)个可以变成……(总之这样下去)
得到\(i\)实际的个数为\(\left\lfloor\frac{\left\lfloor\frac{\left\lfloor\frac{c_1}{2}\right\rfloor+c_2}{2}\right\rfloor+c_3}{2}\right\rfloor....\)无限嵌套,这个下取整好烦啊,把柿子化简为递推式得到:
\(f_i= \left\lfloor\dfrac{f_{i-1}+c_i}{2}\right\rfloor\)
这个柿子会清爽很多,含义是:\(i\)给\(i+1\)对\(i+1\)贡献的量,值\(i\)的个数为\(f_{i-1}+c_i\)。
所以最后求的是最大的 \(i\) 满足\(f_{i-1}+c_i> 0\)
首先\(a\)中的最大值\(mx\)肯定是存在的,所以只用考虑大于\(mx\)出现的最大值,而且这部分的\(c_i=0\),即问题转化为\(f_{i-1}>0\)的最大\(i\)
考虑维护\(f_i\),每次修改相当于一个\(c_i++\)另一个\(c_j--\)。
\(c_i++/--\)对\(f\)的贡献,取决于下取整分子的奇偶性
因此维护\(g_i\)表示\(f_{i-1}+c_i\)为奇(1)/偶(0)
显然\(c_i++\)只会在\(g_i\)为奇数的时候使\(f_i++\),\(f_i++\)又往\(f_{i+1}\)贡献。发现是找到
从\(i\)开始到\(r\)满足\(g\)都为\(1\)的极大段**(\(g_{r+1}=0\)),然后把\(f_l....f_{r}\)区间+1,\(g_l...g_{r+1}\)区间反转,别忘了\(g_{r+1}\)也需要反转(我为这个调了好久)。
\(c_i--\)的增量以及奇偶性判断恰好是反过来的。

因此,我们需要:区间/单点修改(加)区间(单点)查询找从\(l\)开始\(g\)为\(k\)的极长段找最靠右的\(f_i>0\)的\(i\)
最后一个操作直接二分,倒数第二个操作先要找到划分(找到的顺序自然是从左往右的),然后对于一个划分如果全部满足就结束讨论下一个,否则再分治(二分)下去。因为只有一个划分(区间)会分治下去,再加上所有的操作总复杂度为\(O(nlogn)\)

然而我看到其它人很短的代码,就知道我的思路太逊了,不过能自己解出来题也很开心啦。

code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,q,a[N],c[N],F[N],ls[N],nd,rs[N];

priority_queue<int> Q;
int D[N];	//可删堆

void Q_del() {
	while(!Q.empty()&&D[Q.top()]) {D[Q.top()]--;Q.pop();}
}

struct seg {
	int l,r,len,tg,tf,g,f;
}T[N];

void P_dw(int x) {
	if(T[x].tg!=-1) {
		T[ls[x]].tg=T[rs[x]].tg=T[x].tg;
		if(!T[x].tg) {T[ls[x]].g=T[rs[x]].g=0;}
		else {T[ls[x]].g=T[ls[x]].len;T[rs[x]].g=T[rs[x]].len;}
		T[x].tg=-1;
	}
	if(T[x].tf) {
		T[ls[x]].tf+=T[x].tf;T[rs[x]].tf+=T[x].tf;
		T[ls[x]].f+=T[x].tf*T[ls[x]].len;T[rs[x]].f+=T[x].tf*T[rs[x]].len;
		T[x].tf=0;
	}
}
void P_up(int x) {
	T[x].g=T[ls[x]].g+T[rs[x]].g;
	T[x].f=T[ls[x]].f+T[rs[x]].f;
}

int Query(int x,int p) {
	if(T[x].l==T[x].r) {return T[x].g;}
	P_dw(x);
	int mid=(T[x].l+T[x].r)>>1;
	return (p<=mid)?Query(ls[x],p):Query(rs[x],p);
}

void Build(int &x,int l,int r) {
	x=++nd; T[x]=(seg){l,r,r-l+1,-1,0,0,0};
	if(l==r) {T[x].f=F[l];T[x].g=((F[l-1]+c[l])&1);return;}
	int mid=(l+r)>>1;
	Build(ls[x],l,mid),Build(rs[x],mid+1,r);
	P_up(x);
}

void Update(int x,int l,int r,int dg,int df) {
	if(l<=T[x].l&&T[x].r<=r) {
		T[x].f+=df*T[x].len;T[x].g=(!dg)?0:T[x].len;
		T[x].tf+=df;T[x].tg=dg;
		return;
	}
	P_dw(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(l<=mid) Update(ls[x],l,r,dg,df);
	if(r>mid) Update(rs[x],l,r,dg,df);
	P_up(x);
}

void update(int x,int p) {	//g[p]^1
	if(T[x].l==T[x].r) {T[x].g^=1;return;}
	P_dw(x);
	int mid=(T[x].l+T[x].r)>>1;
	(p<=mid)?update(ls[x],p):update(rs[x],p);
	P_up(x);
}

//g整段的值是否为vf 
bool check(int x,int vg) {return T[x].g==(!vg?0:T[x].len);}

int findG(int x,int L,int vg) {	//the rightest G (左边能满足,右边才可以)
	if(T[x].r<L)return -1;
	if(T[x].l==T[x].r) {
		if(!check(x,vg))return -1;
		return T[x].l;
	}
	if(T[x].l>=L) {		//一段划分
		if(check(x,vg)) return T[x].r;
		P_dw(x);
		if(check(ls[x],vg)) {return max(T[ls[x]].r,findG(rs[x],L,vg));}
		else return findG(ls[x],L,vg);
	}
	P_dw(x);
	int mid=T[ls[x]].r;
	if(mid<L) return findG(rs[x],L,vg);
	int w=findG(ls[x],L,vg);	//先找到 [L,n]的划分(从左到右)
	return w==mid?max(w,findG(rs[x],L,vg)):w;
}

int findF(int x,int L) {	//the rightest F(只要最右边有一个满足了即可)
	if(T[x].r<L) {return -1;}
	if(T[x].l==T[x].r) {
		assert(T[x].f>=0);
		if(!T[x].f) return -1;
		return T[x].l;
	}
	P_dw(x);
	assert(T[rs[x]].f>=0);
	if(!T[rs[x]].f) return findF(ls[x],L);
	return findF(rs[x],L);
}



void Del(int x) {
	int w=Query(1,x);
//	printf("Del x=%d c[x]=%d w=%d\n",x,c[x],w);
	if(!(w&1)) {
		int r=findG(1,x,0);
		assert(r!=-1); //*
//		printf("!r=%d\n",r);
		Update(1,x,r,1,-1);
		if(r<m)update(1,r+1);
	}
	else {update(1,x);}
	c[x]--;
}

void Add(int x) {
	int w=Query(1,x);
//	printf("Add x=%d c[x]=%d w=%d\n",x,c[x],w);
	if(w&1) {
		int r=findG(1,x,1);
		assert(r!=-1);
//		printf("!r=%d\n",r);
		Update(1,x,r,0,1);
		if(r<m)update(1,r+1); 
	}
	else {update(1,x);}
	c[x]++;
}


int main() {
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++){scanf("%d",&a[i]);c[a[i]]++;Q.push(a[i]);}
	m=2e5+20;	//+log次
	for(int i=1;i<=m;i++) {F[i]=(F[i-1]+c[i])/2;}
	int rt;Build(rt,1,m);
	while(q--) {
		int k,v;
		scanf("%d%d",&k,&v);
		D[a[k]]++;Q.push(v);Q_del();
		Del(a[k]),Add(v);
		a[k]=v;
		int mx=Q.top();
//		printf("mx=%d\n",mx);
		int r=findF(1,mx);
//		printf("r=%d\n",r);
		printf("%d\n",(r==-1)?mx:r+1);
	}
	
	return 0;
}

//完结撒花 

标签:Koro,return,rs,int,Professor,tf,ls,cf1705E,tg
来源: https://www.cnblogs.com/bestime/p/16484410.html

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

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

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

ICode9版权所有