CSPCCF202212-04聚集方差骗分(55分)

小弱鸡准备参加csp认证,记录一下自己做题

csp认证往年题也做了不少套了,第四题最高才得过30分(捂脸),希望有大佬路过教一手

//2023.9.1又过了两个点,现在55分了

 

 

 

 

 这题按照我的理解,就是找到每棵树所有子节点中价值和自己最接近的一个,并平方二者之差,将所有价值输出,所以可以使用set对数据进行维护,再使用二分法查找来优化时间复杂度。40分做法可以直接使用数组存储然后暴力。这里就不贴详细代码了

第3-5个子任务都有特殊性质,可以做特定优化来节省时间。

任务3的pi=i-1,说明这是一条链,我们可以从后往前进行处理,每添加一个节点就用lower_bound来找到相邻值再进行更改,最后用stack存储答案,最后输出。

multiset<no> s;
		multiset<no>::iterator l,r,ll,rr;
		for(int i=2;i<=n;i++) scanf("%lld",&p[i]);
		for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
		if(p[3]==2){
			stack<long long> ans;
			ans.push(0);
			s.insert({n,b[n]});
			for(int i=n-1;i>=1;i--){
				r=s.upper_bound({0,b[i]});
				rr=r;
				rr++;
				l=r;
				l--;
				ll=l;
				ll--;
				long long in=ans.top();
				if(r==s.begin()){	//插入的数在最左侧
					in+=(b[i]-r->num)*(b[i]-r->num);
					link[i]=2;
					if(link[r->id]==0){
						in+=(b[i]-r->num)*(b[i]-r->num);
						link[r->id]=1;
					}
					else{
						long long change=r->num-b[i];
						if((rr->num-r->num)*(rr->num-r->num)>change*change){
							link[r->id]=1;
							in-=(rr->num-r->num)*(rr->num-r->num);
							in+=change*change;
						}
					}
				}
				else if(r==s.end()){	//插入的数在最右侧
					in+=(b[i]-l->num)*(b[i]-l->num);
					link[i]=1;
					if(link[l->id]==0){
						in+=(b[i]-l->num)*(b[i]-l->num);
						link[l->id]=2;
					}
					else{
						long long change=l->num-b[i];
						if((ll->num-l->num)*(ll->num-l->num)>change*change){
							link[l->id]=2;
							in-=(ll->num-l->num)*(ll->num-l->num);
							in+=change*change;
						}
					}
				}
				else{	//插入的数在中间
					if(link[l->id]==2){
						long long x=r->num-l->num,y=b[i]-l->num;
						in-=x*x;
						in+=y*y;
					}
					if(link[r->id]==1){
						long long x=r->num-l->num,y=b[i]-r->num;
						in-=x*x;
						in+=y*y;
					}
					if(link[l->id]==1){
						long long x=l->num-ll->num,y=b[i]-l->num;
						if(x*x>y*y){
							in-=x*x;
							in+=y*y;
							link[l->id]=2;
						}
					}
					if(link[r->id]==2){
						long long x=rr->num-r->num,y=b[i]-r->num;
						if(x*x>y*y){
							in-=x*x;
							in+=y*y;
							link[r->id]=1;
						}
					}
					long long lnum=l->num-b[i],rnum=r->num-b[i];
					if(lnum*lnum<rnum*rnum){
						link[i]=1;
						in+=lnum*lnum;
					}
					else{
						link[i]=2;
						in+=rnum*rnum;
					}
				}
				s.insert({i,b[i]});
				ans.push(in);
			}
			while(!ans.empty()){
				printf("%lld\n",ans.top());
				ans.pop();
			}
		

任务4pi=i/2,说明这是一棵二叉树,可以使用归并排序来对数据进行处理,(但是我懒得写了)如果实现了可以得70分

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值