小弱鸡准备参加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分