bzoj3011
2024-09-08 09:41:02
可并堆
复习一下可并堆
维护一个大跟堆,每次把节点儿子打上边权标记,然后合并,可并堆上维护一个size,每次把大于l的弹出,size就是答案
程序中那个d写l和r速度差不多,我写l是表示右儿子到u的最长距离
#include<bits/stdc++.h>
using namespace std;
const int N = ;
struct edge {
int to;
long long w;
edge(int to = , long long w = ) : to(to), w(w) {}
};
int n;
long long L;
long long dis[N], tag[N];
int root[N], l[N], r[N], d[N], ans[N], size[N];
vector<edge> G[N];
void pushdown(int x)
{
if(tag[x] == ) return;
tag[l[x]] += tag[x];
dis[l[x]] += tag[x];
tag[r[x]] += tag[x];
dis[r[x]] += tag[x];
tag[x] = ;
}
int merge(int u, int v)
{
if(!u) return v;
if(!v) return u;
pushdown(u);
pushdown(v);
if(dis[u] < dis[v]) swap(u, v);
r[u] = merge(r[u], v);
if(d[r[u]] > d[l[u]]) swap(l[u], r[u]);
d[u] = d[l[u]] + ;
size[u] = size[l[u]] + size[r[u]] + ;
return u;
}
void dfs(int u)
{
root[u] = u;
size[u] = ;
for(int i = ; i < G[u].size(); ++i)
{
edge e = G[u][i];
dfs(e.to);
tag[root[e.to]] += e.w;
dis[root[e.to]] += e.w;
root[u] = merge(root[u], root[e.to]);
}
while(dis[root[u]] > L && root[u]) root[u] = merge(l[root[u]], r[root[u]]);
ans[u] = size[root[u]];
}
int main()
{
scanf("%d%lld", &n, &L);
for(int i = ; i <= n; ++i)
{
int u;
long long len;
scanf("%d%lld", &u, &len);
G[u].push_back(edge(i, len));
}
dfs();
for(int i = ; i <= n; ++i) printf("%d\n", ans[i]);
return ;
}
最新文章
- flume 不报错但是不能正常使用
- js基础篇——原型与原型链的详细理解
- asp.net获取站点根目录下子目录的名称
- 我对windows消息机制的理解(参考深入浅出MFC,欢迎批评指正!!)
- CSS基础选择器温故-1
- chart.js图表库案例赏析,饼图添加文字
- C# ZXing.Net生成二维码、识别二维码、生成带Logo的二维码(二)
- 第 7 章 MySQL 数据库锁定机制
- 【BZOJ4003】【JLOI2015】城池攻占
- flex布局justify-content属性和align-items属性设置
- error LNK1169 找到一个或多个多重定义的符号的解决方法
- Typecho——数据库无法连接问题
- 洛谷P1414又是毕业季二题解
- Expo大作战(三十三)--expo sdk api之MapView(地图),MailComposer(磁力传感计),Lottie(动画)
- [转帖] 常见的cmd命令
- JEECG 命名规范
- Java虚拟机笔记(一):类加载机制
- 给定随机数列求第k大的数字
- 解决不能在本地使用JQuery load的方法
- Ubuntu之No module named cv2