弱省互测#1 t3
题意
给出一棵n个点的树,求包含1号点的第k小的连通块权值和。(n<=105)
分析
k小一般考虑堆...
题解
堆中关键字为s(x)+min(a),其中s(x)表示x状态的权值和,min(a)表示x状态相邻的不在x里的的点的最小权值。
每一次从堆中弹出最小的,然后用这个来拓展。
可以证明,这样第k次弹出来的状态x∪a就是k小的。
证明很简单,堆中的都是待拓展状态,每一次取出来x∪a的将来再也不会有状态的权值和小于这个状态。
维护相邻的点我们可以用可持久化堆搞。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MX=8000005; //超过这个数这份代码别想活了【捂脸熊
struct node *null;
struct node {
node *c[2];
int x, w, s;
void up() { s=1+c[0]->s+c[1]->s; if(c[0]->s<c[1]->s) swap(c[0], c[1]); }
}pool[MX], *iT=pool;
int cc=2;
node *newnode() {
node *x=iT++; ++cc; if(cc>=MX) { puts("err"); exit(0); }
x->c[0]=x->c[1]=null; x->x=-1; x->w=0; x->s=0;
return x;
}
void cpy(node *x, node *y) {
x->x=y->x; x->w=y->w; x->s=y->s;
x->c[0]=y->c[0]; x->c[1]=y->c[1];
}
void init() {
null=iT++;
null->c[0]=null->c[1]=null;
null->x=0; null->w=0; null->s=0;
}
node *merge(node *l, node *r) {
if(l==null) return r;
if(r==null) return l;
node *x=newnode();
if(l->w<=r->w) { cpy(x, l); x->c[1]=merge(x->c[1], r); }
else { cpy(x, r); x->c[1]=merge(x->c[1], l); }
x->up();
return x;
}
node *ins(node *x, node *y) {
if(x==null) return y;
node *p=x;
if(y->w<=x->w) p=y, p->c[0]=x;
else x->c[1]=ins(x->c[1], y);
p->up();
return p;
}
node *ins(node *x, int id, int w, int flag=1) {
node *y=newnode(); y->x=id; y->w=w; y->s=1;
return flag?merge(x, y):ins(x, y);
}
node *del(node *x) { return merge(x->c[0], x->c[1]); }
struct ip {
node *x; ll sum;
bool operator<(const ip &a) const { return sum<a.sum; }
};
multiset<ip> q;
const int N=100005;
int ihead[N], f[N], cnt, n, K;
struct E { int next, to, w; }e[N<<1];
void add(int x, int y, int w) {
e[++cnt]=(E){ihead[x], y, w}; ihead[x]=cnt;
e[++cnt]=(E){ihead[y], x, w}; ihead[y]=cnt;
}
node *root[N];
int main() {
init();
scanf("%d%d", &n, &K);
for(int i=2; i<=n; ++i) {
int w;
scanf("%d%d", &f[i], &w);
add(i, f[i], w);
}
node *rt=null;
for(int x=1; x<=n; ++x) {
root[x]=null;
for(int i=ihead[x]; i; i=e[i].next) if(e[i].to!=f[x])
root[x]=ins(root[x], e[i].to, e[i].w, 0);
}
root[n+1]=ins(null, 1, 0, 0);
q.insert((ip){root[n+1], 0});
ll ans=0; int cnt=0; ip t;
multiset<ip>::iterator it;
while(1) {
if(q.size()==0) break;
it=q.begin(); q.erase(it);
t=*it;
ans=t.sum;
node *now=t.x;
if(now==null) continue;
rt=del(now); if(rt!=null) q.insert((ip){rt, t.sum-now->w+rt->w});
rt=merge(rt, root[now->x]);
q.insert((ip){rt, t.sum+rt->w});
++cnt; if(cnt==K) { ans=t.sum; break; }
if((int)q.size()>K) { it=q.end(); q.erase(--it); }
}
printf("%lld\n", ans%998244353);
return 0;
}
博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2014-11-22 高精度模板2(带符号压位加减乘除开方封包)
2014-11-22 【BZOJ】1004: [HNOI2008]Cards(置换群+polya+burnside)
2014-11-22 【BZOJ】1500: [NOI2005]维修数列(splay+变态题)