【Comet OJ - Contest #8 F 黄金体验】【lct】

题意

有一棵 n n n个节点的树,每个点有一个初始权值 w i w_i wi,要求支持两种操作:
1、使 x x x的点权增加 y y y
2、给出 k k k,选定 k k k个点使得包含这 k k k个点的最小联通子图点权和最大,你只需要输出这个最大值。
n , q ≤ 1 0 5 n,q\le10^5 n,q105

分析

k = 2 k=2 k=2,显然选的是带权最长链。
可以发现 k k k每增加 1 1 1,新的答案显然是在原来最优方案的基础上,新加入一个叶节点。
暴力的做法是先找到带权最长链,使链上点的点权变为 0 0 0,然后每次找从直径端点开始的最长链,再把最长链上点权变为 0 0 0.
可以发现这个过程实际上就是从带权直径的一个端点为根作长链剖分,然后选出前 k k k大的链作为答案。
可以用lct来维护长链剖分,每次更新点权后,不断往上更新长链,相当于lct的access操作。
由于必须要以带权直径的端点作为根,所以修改点权后可能要进行换根操作。具体实现的时候可以在access到直径的时候,选出对应点较大的一端包含的端点换为根,然后正常维护即可。
还要用数据结构来记录每一条链的权值。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>

typedef long long LL;

const int N=100005;
const LL inf=(LL)1e14;

int n,q,rt,cnt,last[N];
LL dis[N],w[N],rtd;
struct tree{
   int l,r,s,fa;LL w;bool rev;}t[N];
struct edge{
   int to,next;}e[N*2];
std::multiset<LL> se;
std::multiset<LL>::iterator it;

struct Segtree
{
   
	int rt,sz;
	struct tree{
   int l,r,s;LL w;}t[N*80];
	
	void ins(int &d,LL l,LL r,LL x,int y)
	{
   
		if (!d) d=++sz;
		t[d].s+=y;t[d].w+=x*y;
		if (l==r) return
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值