题解:P6544 [CEOI2014] Cake
P6544 解题报告
前言
感觉没有紫……
但是评了我也没意见。
思路分析
首先考虑怎样计算答案。
如果 在 的左侧,那么设 为 的最大值, 为 中最靠左的 的位置,那么答案为 。
应该不难理解。想要吃掉 ,必须吃掉 的所有蛋糕,和 中部分比 小的蛋糕。
可以直接线段树二分解决。
瓶颈在于修改。
发现这个修改非常神秘,它只修改值的大小关系,但是不修改具体的值。
因为 非常不正常,所以考虑从这里入手解决。
发现如果我们只维护前 大所在的位置,那么修改时可以把前 大的值整体向前平移一段距离,给第 大留出位置,然后把第 大往后的排名整体后移。
感觉上比维护实数值好写多了。
然后就做完了。
实际上,只需要维护一棵支持单点修改,查询最大值,查询区间 的最靠左/右的下标的线段树就行了。
总体复杂度 ,在洛谷上跑进了 300 ms。
代码实现
感觉上不是很难写,但是从想到做完还是用了 1 h。
#include<bits/stdc++.h>
using namespace std;
int n,m,a,pos,maxn,sum,num,id,e,d[250005],c[250005];
char op;
int val[500005],ls[500005],rs[500005],dcnt,rt;
void pushup(int x){
val[x]=max(val[ls[x]],val[rs[x]]);
}
void build(int l,int r,int &x){
x=++dcnt;
if(l==r){
val[x]=d[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,ls[x]);
build(mid+1,r,rs[x]);
pushup(x);
}
void modify(int l,int r,int pos,int k,int x){
if(l==r && l==pos){
val[x]=k;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) modify(l,mid,pos,k,ls[x]);
else modify(mid+1,r,pos,k,rs[x]);
pushup(x);
}
int query(int l,int r,int ql,int qr,int x){
if(ql<=l && r<=qr){
return val[x];
}
int mid=(l+r)>>1,ans=0;
if(ql<=mid) ans=max(ans,query(l,mid,ql,qr,ls[x]));
if(qr>=mid+1) ans=max(ans,query(mid+1,r,ql,qr,rs[x]));
return ans;
}
int find_l(int l,int r,int ql,int qr,int k,int x){
if(l==r){
if(val[x]<k) return -1;
else return l;
}
int mid=(l+r)>>1;
if(ql<=mid && val[ls[x]]>=k){
int ans=find_l(l,mid,ql,qr,k,ls[x]);
if(ans!=-1) return ans;
}
if(qr>=mid+1){
return find_l(mid+1,r,ql,qr,k,rs[x]);
}else return -1;
}
int find_r(int l,int r,int ql,int qr,int k,int x){
if(l==r){
if(val[x]<k) return -1;
else return l;
}
int mid=(l+r)>>1;
if(qr>=mid+1 && val[rs[x]]>=k){
int ans=find_r(mid+1,r,ql,qr,k,rs[x]);
if(ans!=-1) return ans;
}
if(ql<=mid){
return find_r(l,mid,ql,qr,k,ls[x]);
}else return -1;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>a;
for(int i=1;i<=n;i++){
cin>>d[i];
if(n-d[i]+1<=10) c[n-d[i]+1]=i;
}
build(1,n,rt);
cin>>m;
sum=n;
for(int i=1;i<=m;i++){
cin>>op;
if(op=='F'){
cin>>pos;
if(pos==a){
cout<<0<<'\n';
}else if(pos<a){
maxn=query(1,n,pos,a-1,rt);
int k=(a==n?-1:find_l(1,n,a+1,n,maxn,rt));
if(k==-1) k=n+1;
cout<<k-pos-1<<'\n';
}else{
maxn=query(1,n,a+1,pos,rt);
int k=(a==1?-1:find_r(1,n,1,a-1,maxn,rt));
if(k==-1) k=0;
cout<<pos-k-1<<'\n';
}
}else{
int lst=min(n,10);
cin>>pos>>num;
for(int i=1;i<=10;i++){
if(c[i]==pos) lst=i;
}
for(int i=lst-1;i>=num;i--){
c[i+1]=c[i];
}
c[num]=pos;
for(int i=num;i>=1;i--){
sum++;
modify(1,n,c[i],sum,rt);
}
}
}
return 0;
}
后记
最后要谴责 nfls 机子慢还要开小时限,使某些人的正解被卡常了。
还有我不是高二的老年选手……
本文作者:Kenma
本文链接:https://www.cnblogs.com/Kenma/p/18689770
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步