CF1987E Wonderful Tree!
CF1987E 题解
题意
给定一棵大小为
题解
麻了,赛后十五分钟调出来,可惜为时已晚。
读懂题之后容易发现,题目最核心的地方在于当我们需要一个节点
也就是说,如果一个节点需要
那么我们就可以令
对于新定义的权值
这是怎么来的呢?当我们按原题意操作了一条链时,注意到对链上除最深的节点也就是链尾之外,其他的节点权值与其儿子节点权值和之差保持不变;而链尾的这个差(也就是
所以对于每个
具体实现就是在遍历过程中对每个节点维护其后代 压榨利用的点集,如果自身 std::vector
维护点集并按降序维护,因为将自身纳入点集时我们没有 push_front()
这个函数 。
归并帮我们在合并时压掉了一个
const ll maxn=5e3+5;
ll a[maxn],siz[maxn],dep[maxn];
ll b[maxn],ans;
ll n;
vector<ll>e[maxn];
void dfs(ll x){//预处理出 b 值
siz[x]=1;
b[x]=-a[x];
for(auto v:e[x]){
dep[v]=dep[x]+1;//标 dep 便于计算代价
b[x]+=a[v];
dfs(v);
siz[x]+=siz[v];
}
if(siz[x]==1)b[x]=1ll<<31;//叶子的 b 值为正无穷
}
vector<ll>work(ll x){//返回的是点集
vector<ll>lst;//自己的点集
for(auto v:e[x]){
vector<ll>res=work(v);
vector<ll>tmp;
ll l=0,r=0,len1=lst.size(),len2=res.size();
while(l<len1||r<len2){//归并
if(l==len1)tmp.push_back(res[r++]);
else if(r==len2)tmp.push_back(lst[l++]);
else if(dep[lst[l]]>dep[res[r]])tmp.push_back(lst[l++]);
else tmp.push_back(res[r++]);
}
lst.swap(tmp);
}
if(b[x]>0)lst.push_back(x);//b>0 则放入自身
else if(b[x]<0){
ll p=lst.size()-1;//不用验空,b<0 其必有儿子,有儿子必有后代为叶子
while(b[x]<0){
ll it=lst[p];
ll sum=min(-b[x],b[it]);//要么直接填满,要么把这个用完
b[it]-=sum,b[x]+=sum;
ans+=sum*(dep[it]-dep[x]);//代价
if(b[it]==0)p--,lst.pop_back();//用完扔掉不然单调性没法保证
}
}
return lst;//自身点集向上合并
}
void solve(){
n=R;
ans=0;//清多测
for(ll i=1;i<=n;i++){
a[i]=R;
e[i].clear();//这里好一点的写法是用 tmp.swap(e[i]) 彻底释放空间
//但由于题目保证了数据总和,抢时间就不写太麻烦了
}
for(ll i=2;i<=n;i++)e[R].push_back(i);
dfs(1);
work(1);
we(ans);
return ;
}
赛时还是不要放弃啊,我要是中间没有开摆这题就有时间切掉了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现